gateway-1.4.3/ 0000755 0001750 0001750 00000000000 11145564453 012226 5 ustar soren soren gateway-1.4.3/wap/ 0000755 0001750 0001750 00000000000 11142334240 012777 5 ustar soren soren gateway-1.4.3/wap/wtp_pack.h 0000644 0001750 0001750 00000011535 11132672003 014766 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_pack.h - WTP implementation, message module header
*
* By Aarno Syvnen for WapIT Ltd.
*/
#ifndef WTP_SEND_H
#define WTP_SEND_H
#include "gwlib/gwlib.h"
#include "wap_events.h"
#include "wtp_init.h"
#include "wtp_resp.h"
#include "wtp.h"
#include "wap.h"
/*
* Create a datagram event, having invoke PDU as user data. Fetches address,
* tid and tid_new from the initiator state machine, other fields from event.
* Only for the wtp initiator.
*
* Return message to be sent.
*/
WAPEvent *wtp_pack_invoke(WTPInitMachine *init_machine, WAPEvent *event);
/*
* Create a datagram event, having result PDU as user data. Fetches SDU
* from WTP event, address four-tuple and machine state information
* (are we resending the packet) from WTP machine. Handles all
* errors by itself. Returns message, if OK, else NULL. Only for wtp
* responder.
*/
WAPEvent *wtp_pack_result(WTPRespMachine *resp_machine, WAPEvent *event);
/*
* Same as above but for a segmented result.
*/
WAPEvent *wtp_pack_sar_result(WTPRespMachine *resp_machine, int psn);
/*
* Create a datagram event, having abort PDU as user data. Fetches SDU
* from WTP event, address four-tuple from WTP machine.
* Handles all errors by itself. Both for wtp initiator and responder.
*/
WAPEvent *wtp_pack_abort(long abort_type, long abort_reason, long tid,
WAPAddrTuple *address);
/*
* Create a datagram event, having ack PDU as user data. Creates SDU by
* itself, fetches address four-tuple and machine state from WTP machine.
* Ack_type is a flag telling whether we are doing tid verification or not,
* rid_flag tells are we retransmitting. Handles all errors by itself.
* Both for wtp initiator and responder.
*/
WAPEvent *wtp_pack_ack(long ack_type, int rid_flag, long tid,
WAPAddrTuple *address);
/*
* Same as above but for a segmented ack
*/
WAPEvent *wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn);
/*
* Set or unset the retransmission indicator on a PDU that has already
* been packed as a datagram. dgram must be of type T_DUnitdata_Req.
*/
void wtp_pack_set_rid(WAPEvent *dgram, long rid);
#endif
gateway-1.4.3/wap/timers.c 0000644 0001750 0001750 00000037563 11132672003 014465 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* timers.c - timers and set of timers, mainly for WTP.
*
* See timers.h for a description of the interface.
*/
#include
#include "gwlib/gwlib.h"
#include "wap_events.h"
#include "timers.h"
/*
* Active timers are stored in a TimerHeap. It is a partially ordered
* array. Each element i is the child of element i/2 (rounded down),
* and a child never elapses before its parent. The result is that
* element 0, the top of the heap, is always the first timer to
* elapse. The heap is kept in this partial order by all operations on
* it. Maintaining a partial order is much cheaper than maintaining
* a sorted list.
* The array will be resized as needed. The size field is the number
* of elements for which space is reserved, and the len field is the
* number of elements actually used. The elements used will always be
* at tab[0] through tab[len-1].
*/
struct TimerHeap
{
Timer **tab;
long len;
long size;
};
typedef struct TimerHeap TimerHeap;
struct Timerset
{
/*
* This field is set to true when the timer thread should shut down.
*/
volatile sig_atomic_t stopping;
/*
* The entire set is locked for any operation on it. This is
* not as expensive as it sounds because usually each set is
* used by one caller thread and one (internal) timer thread,
* and the timer thread does not wake up very often.
*/
Mutex *mutex;
/*
* Active timers are stored here in a partially ordered structure.
* See the definition of TimerHeap, above, for an explanation.
*/
TimerHeap *heap;
/*
* The thread that watches the top of the heap, and processes
* timers that have elapsed.
*/
long thread;
};
typedef struct Timerset Timerset;
struct Timer
{
/*
* An event is produced on the output list when the
* timer elapses. The timer is not considered to have
* elapsed completely until that pointer has also been
* consumed from this list (by the caller, presumably).
* That is why the timer code sometimes goes back and
* removes a pointer from the output list.
*/
List *output;
/*
* The timer is set to elapse at this time, expressed in
* Unix time format. This field is set to -1 if the timer
* is not active (i.e. in the timer set's heap).
*/
long elapses;
/*
* A duplicate of this event will be put on the output list
* when the timer elapses. It can be NULL if the timer has
* not been started yet.
*/
WAPEvent *event;
/*
* This field is normally NULL, but after the timer elapses
* it points to the event that was put on the output list.
* It is set back to NULL if the event was taken back from
* the list, or if it's confirmed that the event was consumed.
*/
WAPEvent *elapsed_event;
/*
* Index in the timer set's heap. This field is managed by
* the heap operations, and is used to make them faster.
* If this timer is not in the heap, this field is -1.
*/
long index;
};
/*
* Currently we have one timerset (and thus one heap and one thread)
* for all timers. This might change in the future in order to tune
* performance. In that case, it will be necessary to add a "set"
* field to the Timer structure.
*/
static Timerset *timers;
/*
* Used by timer functions to assert that the timer module has been
* intialized.
*/
static int initialized = 0;
/*
* Internal functions
*/
static void abort_elapsed(Timer *timer);
static TimerHeap *heap_create(void);
static void heap_destroy(TimerHeap *heap);
static void heap_delete(TimerHeap *heap, long index);
static int heap_adjust(TimerHeap *heap, long index);
static void heap_insert(TimerHeap *heap, Timer *timer);
static void heap_swap(TimerHeap *heap, long index1, long index2);
static void lock(Timerset *set);
static void unlock(Timerset *set);
static void watch_timers(void *arg); /* The timer thread */
static void elapse_timer(Timer *timer);
void timers_init(void)
{
if (initialized == 0) {
timers = gw_malloc(sizeof(*timers));
timers->mutex = mutex_create();
timers->heap = heap_create();
timers->stopping = 0;
timers->thread = gwthread_create(watch_timers, timers);
}
initialized++;
}
void timers_shutdown(void)
{
if (initialized > 1) {
initialized--;
return;
}
/* Stop all timers. */
if (timers->heap->len > 0)
warning(0, "Timers shutting down with %ld active timers.",
timers->heap->len);
while (timers->heap->len > 0)
gwtimer_stop(timers->heap->tab[0]);
/* Kill timer thread */
timers->stopping = 1;
gwthread_wakeup(timers->thread);
gwthread_join(timers->thread);
initialized = 0;
/* Free resources */
heap_destroy(timers->heap);
mutex_destroy(timers->mutex);
gw_free(timers);
}
Timer *gwtimer_create(List *outputlist)
{
Timer *t;
gw_assert(initialized);
t = gw_malloc(sizeof(*t));
t->elapses = -1;
t->event = NULL;
t->elapsed_event = NULL;
t->index = -1;
t->output = outputlist;
gwlist_add_producer(outputlist);
return t;
}
void gwtimer_destroy(Timer *timer)
{
gw_assert(initialized);
if (timer == NULL)
return;
gwtimer_stop(timer);
gwlist_remove_producer(timer->output);
wap_event_destroy(timer->event);
gw_free(timer);
}
void gwtimer_start(Timer *timer, int interval, WAPEvent *event)
{
int wakeup = 0;
gw_assert(initialized);
gw_assert(timer != NULL);
gw_assert(event != NULL || timer->event != NULL);
lock(timers);
/* Convert to absolute time */
interval += time(NULL);
if (timer->elapses > 0) {
/* Resetting an existing timer. Move it to its new
* position in the heap. */
if (interval < timer->elapses && timer->index == 0)
wakeup = 1;
timer->elapses = interval;
gw_assert(timers->heap->tab[timer->index] == timer);
wakeup |= heap_adjust(timers->heap, timer->index);
} else {
/* Setting a new timer, or resetting an elapsed one.
* First deal with a possible elapse event that may
* still be on the output list. */
abort_elapsed(timer);
/* Then activate the timer. */
timer->elapses = interval;
gw_assert(timer->index < 0);
heap_insert(timers->heap, timer);
wakeup = timer->index == 0; /* Do we have a new top? */
}
if (event != NULL) {
wap_event_destroy(timer->event);
timer->event = event;
}
unlock(timers);
if (wakeup)
gwthread_wakeup(timers->thread);
}
void gwtimer_stop(Timer *timer)
{
gw_assert(initialized);
gw_assert(timer != NULL);
lock(timers);
/*
* If the timer is active, make it inactive and remove it from
* the heap.
*/
if (timer->elapses > 0) {
timer->elapses = -1;
gw_assert(timers->heap->tab[timer->index] == timer);
heap_delete(timers->heap, timer->index);
}
abort_elapsed(timer);
unlock(timers);
}
static void lock(Timerset *set)
{
gw_assert(set != NULL);
mutex_lock(set->mutex);
}
static void unlock(Timerset *set)
{
gw_assert(set != NULL);
mutex_unlock(set->mutex);
}
/*
* Go back and remove this timer's elapse event from the output list,
* to pretend that it didn't elapse after all. This is necessary
* to deal with some races between the timer thread and the caller's
* start/stop actions.
*/
static void abort_elapsed(Timer *timer)
{
long count;
if (timer->elapsed_event == NULL)
return;
count = gwlist_delete_equal(timer->output, timer->elapsed_event);
if (count > 0) {
debug("timers", 0, "Aborting %s timer.",
wap_event_name(timer->elapsed_event->type));
wap_event_destroy(timer->elapsed_event);
}
timer->elapsed_event = NULL;
}
/*
* Create a new timer heap.
*/
static TimerHeap *heap_create(void)
{
TimerHeap *heap;
heap = gw_malloc(sizeof(*heap));
heap->tab = gw_malloc(sizeof(heap->tab[0]));
heap->size = 1;
heap->len = 0;
return heap;
}
static void heap_destroy(TimerHeap *heap)
{
if (heap == NULL)
return;
gw_free(heap->tab);
gw_free(heap);
}
/*
* Remove a timer from the heap. Do this by swapping it with the element
* in the last position, then shortening the heap, then moving the
* swapped element up or down to maintain the partial ordering.
*/
static void heap_delete(TimerHeap *heap, long index)
{
long last;
gw_assert(index >= 0);
gw_assert(index < heap->len);
gw_assert(heap->tab[index]->index == index);
last = heap->len - 1;
heap_swap(heap, index, last);
heap->tab[last]->index = -1;
heap->len--;
if (index != last)
heap_adjust(heap, index);
}
/*
* Add a timer to the heap. Do this by adding it at the end, then
* moving it up or down as necessary to achieve partial ordering.
*/
static void heap_insert(TimerHeap *heap, Timer *timer)
{
heap->len++;
if (heap->len > heap->size) {
heap->tab = gw_realloc(heap->tab,
heap->len * sizeof(heap->tab[0]));
heap->size = heap->len;
}
heap->tab[heap->len - 1] = timer;
timer->index = heap->len - 1;
heap_adjust(heap, timer->index);
}
/*
* Swap two elements of the heap, and update their index fields.
* This is the basic heap operation.
*/
static void heap_swap(TimerHeap *heap, long index1, long index2)
{
Timer *t;
gw_assert(index1 >= 0);
gw_assert(index1 < heap->len);
gw_assert(index2 >= 0);
gw_assert(index2 < heap->len);
if (index1 == index2)
return;
t = heap->tab[index1];
heap->tab[index1] = heap->tab[index2];
heap->tab[index2] = t;
heap->tab[index1]->index = index1;
heap->tab[index2]->index = index2;
}
/*
* The current element has broken the partial ordering of the
* heap (see explanation in the definition of Timerset), and
* it has to be moved up or down until the ordering is restored.
* Return 1 if the timer at the heap's top is now earlier than
* before this operation, otherwise 0.
*/
static int heap_adjust(TimerHeap *heap, long index)
{
Timer *t;
Timer *parent;
long child_index;
/*
* We can assume that the heap was fine before this element's
* elapse time was changed. There are three cases to deal
* with:
* - Element's new elapse time is too small; it should be
* moved toward the top.
* - Element's new elapse time is too large; it should be
* moved toward the bottom.
* - Element's new elapse time still fits here, we don't
* have to do anything.
*/
gw_assert(index >= 0);
gw_assert(index < heap->len);
/* Move to top? */
t = heap->tab[index];
parent = heap->tab[index / 2];
if (t->elapses < parent->elapses) {
/* This will automatically terminate when it reaches
* the top, because in that t == parent. */
do {
heap_swap(heap, index, index / 2);
index = index / 2;
parent = heap->tab[index / 2];
} while (t->elapses < parent->elapses);
/* We're done. Return 1 if we changed the top. */
return index == 0;
}
/* Move to bottom? */
for (; ; ) {
child_index = index * 2;
if (child_index >= heap->len)
return 0; /* Already at bottom */
if (child_index == heap->len - 1) {
/* Only one child */
if (heap->tab[child_index]->elapses < t->elapses)
heap_swap(heap, index, child_index);
break;
}
/* Find out which child elapses first */
if (heap->tab[child_index + 1]->elapses <
heap->tab[child_index]->elapses) {
child_index++;
}
if (heap->tab[child_index]->elapses < t->elapses) {
heap_swap(heap, index, child_index);
index = child_index;
} else {
break;
}
}
return 0;
}
/*
* This timer has elapsed. Do the housekeeping. We have its set locked.
*/
static void elapse_timer(Timer *timer)
{
gw_assert(timer != NULL);
gw_assert(timers != NULL);
/* This must be true because abort_elapsed is always called
* before a timer is activated. */
gw_assert(timer->elapsed_event == NULL);
debug("timers", 0, "%s elapsed.", wap_event_name(timer->event->type));
timer->elapsed_event = wap_event_duplicate(timer->event);
gwlist_produce(timer->output, timer->elapsed_event);
timer->elapses = -1;
}
/*
* Main function for timer thread.
*/
static void watch_timers(void *arg)
{
Timerset *set;
long top_time;
long now;
set = arg;
while (!set->stopping) {
lock(set);
now = time(NULL);
while (set->heap->len > 0 && set->heap->tab[0]->elapses <= now) {
elapse_timer(set->heap->tab[0]);
heap_delete(set->heap, 0);
}
/*
* Now sleep until the next timer elapses. If there isn't one,
* then just sleep very long. We will get woken up if the
* top of the heap changes before we wake.
*/
if (set->heap->len == 0) {
unlock(set);
gwthread_sleep(1000000.0);
} else {
top_time = set->heap->tab[0]->elapses;
unlock(set);
gwthread_sleep(top_time - now);
}
}
}
gateway-1.4.3/wap/timers.h 0000644 0001750 0001750 00000013073 11132672003 014460 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* timers.h - interface to timers and timer sets.
*
* Timers can be set to elapse after a specified number of seconds
* (the "interval"). They can be stopped before elapsing, and the
* interval can be changed.
*
* An "output list" is defined for each timer. When it elapses, an
* event is generated on this list. The event may be removed from
* the output list if the timer is destroyed or extended before the
* event is consumed.
*
* The event to use when a timer elapses is provided by the caller.
* The timer module will "own" it, and be responsible for deallocation.
* This will be true until the event has been consumed from the output
* list (at which point it is owned by the consuming thread).
* While the event is on the output list, it is in a gray area, because
* the timer module might still take it back. This won't be a problem
* as long as you access the event only by consuming it.
*
* Timers work best if the thread that manipulates the timer (the
* "calling thread") is the same thread that consumes the output list.
* This way, it can be guaranteed that the calling thread will not
* see a timer elapse after being destroyed, or while being extended,
* because the elapse event will be deleted during such an operation.
*
* The timer_* functions have been renamed to gwtimer_* to avoid
* a name conflict on Solaris systems.
*/
#ifndef TIMERS_H
#define TIMERS_H
#include "gwlib/gwlib.h"
#include "wap_events.h"
typedef struct Timer Timer;
/*
* Start up the timer system.
* Can be called more than once, in which case multiple shutdowns are
* also required.
*/
void timers_init(void);
/*
* Stop all timers and shut down the timer system.
*/
void timers_shutdown(void);
/*
* Create a timer and tell it to use the specified output list when
* it elapses. Do not start it yet. Return the new timer.
*/
Timer *gwtimer_create(List *outputlist);
/*
* Destroy this timer and free its resources. Stop it first, if needed.
*/
void gwtimer_destroy(Timer *timer);
/*
* Make the timer elapse after 'interval' seconds, at which time it
* will push event 'event' on the output list defined for its timer set.
* - If the timer was already running, these parameters will override
* its old settings.
* - If the timer has already elapsed, try to remove its event from
* the output list.
* If this is not the first time the timer was started, the event
* pointer is allowed to be NULL. In that case the event pointer
* from the previous call to timer_start for this timer is re-used.
* NOTE: Each timer must have a unique event pointer. The caller must
* create the event, and passes control of it to the timer module with
* this call.
*/
void gwtimer_start(Timer *timer, int interval, WAPEvent *event);
/*
* Stop this timer. If it has already elapsed, try to remove its
* event from the output list.
*/
void gwtimer_stop(Timer *timer);
#endif
gateway-1.4.3/wap/wtls.c 0000644 0001750 0001750 00000053475 11132672003 014153 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtls.c: WTLS server-side implementation
*
* Nick Clarey
*/
#include "gwlib/gwlib.h"
#if (HAVE_WTLS_OPENSSL)
#include "wtls.h"
#include "timers.h"
#include "wap_events.h"
#include "wtls_pdu.h"
#include "wtls_statesupport.h"
#include "gw/msg.h"
#include "wtp.h"
/***********************************************************************
* Internal data structures.
*
* List of WTLS Server machines.
*/
static List *wtls_machines = NULL;
/*
* Counter for WTLS Server machine id numbers, to make sure they are unique.
*/
static Counter *wtls_machine_id_counter = NULL;
/*
* Give the status of wtls server layer:
* limbo - not running at all
* running - operating normally
* terminating - waiting for operations to terminate, returning to limbo
*/
static enum { limbo, running, terminating } wtls_run_status = limbo;
/*
* Queue of events to be handled by WTLS Server machines.
*/
static List *wtls_queue = NULL;
/*****************************************************************************
*
* Prototypes of internal functions:
*/
/*
* Create and destroy an uninitialized wtls server state machine.
*/
static WTLSMachine* wtls_machine_create(WAPAddrTuple *tuple);
static void wtls_machine_create_destroy(void *sm);
static void wtls_machine_destroy(void * p);
/*
* Checks whether the list of wlts server machines includes a specific machine.
*
* The machine in question is identified with with source and destination
* address and port. If the machine does not exist and the event is either;
* - A SEC-Create-Request.req or
* - A T-Unitdata.ind containing a ClientHello packet or
* - A T-Unitdata.ind containing an Alert(no_renegotiation) packet
* a new machine is created and added in the machines data structure.
*
* See WTLS 7.2 for details of this check.
*/
static WTLSMachine *wtls_machine_find_or_create(WAPEvent *event);
/*
* Feed an event to a WTLS Server state machine. Handle all errors by
* itself, do not report them to the caller.
*/
static void wtls_event_handle(WTLSMachine *machine, WAPEvent *event);
/*
* Print a WTLS Server machine state as a string.
*/
static unsigned char *name_wtlser_state(int name);
/*
* Find a WTLS Server machine from the global list of wtls server
* structures that corresponds to the four-tuple of source and destination
* addresses and ports. Return a pointer to the machine, or NULL if not found.
*/
static WTLSMachine *wtls_machine_find(WAPAddrTuple *tuple, long mid);
static void main_thread(void *);
static WTLSMachine *find_wtls_machine_using_mid(long mid);
static void add_wtls_address(Msg *msg, WTLSMachine *wtls_machine);
/* The match* functions are used for searches through lists */
static int match_handshake_type(void* item, void* pattern);
static int match_pdu_type(void* item, void* pattern);
/*static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data);
static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason);
static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm); */
/******************************************************************************
*
* EXTERNAL FUNCTIONS:
*
*/
WAPEvent *wtls_unpack_wdp_datagram(Msg *msg)
{
WAPEvent* unitdataIndEvent;
List* wtlsPayloadList;
/* Dump the Msg */
msg_dump(msg,0);
/* Then, stuff it into a T_Unitdata_Ind Event */
unitdataIndEvent = wap_event_create(T_Unitdata_Ind);
info(0,"Event created");
/* Firstly, the address */
unitdataIndEvent->u.T_Unitdata_Ind.addr_tuple =
wap_addr_tuple_create(msg->wdp_datagram.source_address,
msg->wdp_datagram.source_port,
msg->wdp_datagram.destination_address,
msg->wdp_datagram.destination_port);
info(0,"Set address and stuff");
/* Attempt to stuff this baby into a list-of-WTLS-PDUs */
wtlsPayloadList = wtls_unpack_payloadlist (msg->wdp_datagram.user_data);
info(0,"Datagram unpacked!");
/* Then, the pdu material */
unitdataIndEvent->u.T_Unitdata_Ind.pdu_list = wtlsPayloadList;
/* And return the event */
return unitdataIndEvent;
}
void wtls_init(void) {
/* Initialise our various lists and counters */
wtls_machines = gwlist_create();
wtls_machine_id_counter = counter_create();
wtls_queue = gwlist_create();
gwlist_add_producer(wtls_queue);
/* Idiot check - ensure that we are able to start running */
gw_assert(wtls_run_status == limbo);
wtls_run_status = running;
gwthread_create(main_thread, NULL);
}
void wtls_shutdown(void) {
/* Make sure that we're actually running; if so, then
prepare for termination */
gw_assert(wtls_run_status == running);
wtls_run_status = terminating;
gwlist_remove_producer(wtls_queue);
gwthread_join_every(main_thread);
/* Print out a friendly message stating that we're going to die */
debug("wap.wtls", 0, "wtls_shutdown: %ld wtls machines left",
gwlist_len(wtls_machines));
/* And clean up nicely after ourselves */
gwlist_destroy(wtls_machines, wtls_machine_destroy);
gwlist_destroy(wtls_queue, wap_event_destroy_item);
counter_destroy(wtls_machine_id_counter);
}
void wtls_dispatch_event(WAPEvent *event) {
/* Stick the event on the incoming events queue */
gwlist_produce(wtls_queue, event);
}
int wtls_get_address_tuple(long mid, WAPAddrTuple **tuple) {
WTLSMachine *sm;
sm = find_wtls_machine_using_mid(mid);
if (sm == NULL)
return -1;
*tuple = wap_addr_tuple_duplicate(sm->addr_tuple);
return 0;
}
void send_alert(int alertLevel, int alertDescription, WTLSMachine* wtls_machine) {
wtls_Payload* alertPayload;
wtls_PDU* alertPDU;
Octstr* packedAlert;
Msg* msg = NULL;
alertPDU = (wtls_PDU*) wtls_pdu_create(Alert_PDU);
alertPDU->u.alert.level = alertLevel;
alertPDU->u.alert.desc = alertDescription;
/* Here's where we should get the current checksum from the wtls_machine */
alertPDU->u.alert.chksum = 0;
/* Pack the PDU */
msg = msg_create(wdp_datagram);
add_wtls_address(msg, wtls_machine);
/* Pack the message */
alertPayload = wtls_pdu_pack(alertPDU, wtls_machine);
packedAlert = (Octstr*) wtls_payload_pack(alertPayload);
msg->wdp_datagram.user_data = packedAlert;
/* And destroy the structure */
wtls_payload_destroy(alertPayload);
alertPayload = NULL;
/* Send it off */
write_to_bearerbox(msg);
}
void clear_queuedpdus(WTLSMachine* wtls_machine)
{
}
void add_pdu(WTLSMachine* wtls_machine, wtls_PDU* pduToAdd)
{
int currentLength;
wtls_Payload* payloadToAdd;
Octstr* packedPDU;
/* Check to see if we've already allocated some memory for the list */
if (wtls_machine->packet_to_send == NULL) {
wtls_machine->packet_to_send = octstr_create("");
}
/* Pack and encrypt the pdu */
payloadToAdd = wtls_pdu_pack(pduToAdd, wtls_machine);
/* If the pdu is a Handshake pdu, append the Octstr to our wtls_machine's
exchanged_handshakes Octstr */
packedPDU = wtls_payload_pack(payloadToAdd);
/* Add it to our list */
currentLength = octstr_len(wtls_machine->packet_to_send);
octstr_insert(wtls_machine->packet_to_send, packedPDU, currentLength);
}
/*
* Send the pdu_to_send list to the destination specified by the address in the machine
* structure. Don't return anything, handle all errors internally.
*/
void send_queuedpdus(WTLSMachine* wtls_machine)
{
Msg* msg = NULL;
gw_assert(wtls_machine->packet_to_send != NULL);
/* Pack the PDU */
msg = msg_create(wdp_datagram);
add_wtls_address(msg, wtls_machine);
msg->wdp_datagram.user_data = octstr_duplicate(wtls_machine->packet_to_send);
/* Send it off */
write_to_bearerbox(msg);
/* Destroy our copy of the sent string */
octstr_destroy(wtls_machine->packet_to_send);
wtls_machine->packet_to_send = NULL;
}
/*
* Add address from state machine.
*/
void add_wtls_address(Msg *msg, WTLSMachine *wtls_machine){
debug("wap.wtls", 0, "adding address");
msg->wdp_datagram.source_address =
octstr_duplicate(wtls_machine->addr_tuple->local->address);
msg->wdp_datagram.source_port = wtls_machine->addr_tuple->local->port;
msg->wdp_datagram.destination_address =
octstr_duplicate(wtls_machine->addr_tuple->remote->address);
msg->wdp_datagram.destination_port =
wtls_machine->addr_tuple->remote->port;
}
/*****************************************************************************
*
* INTERNAL FUNCTIONS:
*
*/
static void main_thread(void *arg) {
WTLSMachine *sm;
WAPEvent *e;
while (wtls_run_status == running &&
(e = gwlist_consume(wtls_queue)) != NULL) {
sm = wtls_machine_find_or_create(e);
if (sm == NULL)
wap_event_destroy(e);
else
wtls_event_handle(sm, e);
}
}
/*
* Give the name of a WTLS Server state in a readable form.
*/
static unsigned char *name_wtls_state(int s){
switch (s){
#define STATE_NAME(state) case state: return #state;
#define ROW(state, event, condition, action, new_state)
#include "wtls_state-decl.h"
default:
return "unknown state";
}
}
/*
* Feed an event to a WTP responder state machine. Handle all errors yourself,
* do not report them to the caller. Note: Do not put {}s of the else block
* inside the macro definition.
*/
static void wtls_event_handle(WTLSMachine *wtls_machine, WAPEvent *event){
debug("wap.wtls", 0, "WTLS: wtls_machine %ld, state %s, event %s.",
wtls_machine->mid,
name_wtls_state(wtls_machine->state),
wap_event_name(event->type));
/* for T_Unitdata_Ind PDUs */
if(event->type == T_Unitdata_Ind) {
/* if encryption: decrypt all pdus in the list */
if( wtls_machine->encrypted ) {
wtls_decrypt_pdu_list(wtls_machine, event->u.T_Unitdata_Ind.pdu_list);
}
/* add all handshake data to wtls_machine->handshake_data */
//add_all_handshake_data(wtls_machine, event->u.T_Unitdata_Ind.pdu_list);
}
#define STATE_NAME(state)
#define ROW(wtls_state, event_type, condition, action, next_state) \
if (wtls_machine->state == wtls_state && \
event->type == event_type && \
(condition)) { \
action \
wtls_machine->state = next_state; \
debug("wap.wtls", 0, "WTLS %ld: New state %s", wtls_machine->mid, #next_state); \
} else
#include "wtls_state-decl.h"
{
error(0, "WTLS: handle_event: unhandled event!");
debug("wap.wtls", 0, "WTLS: handle_event: Unhandled event was:");
wap_event_destroy(event);
return;
}
if (event != NULL) {
wap_event_destroy(event);
}
if (wtls_machine->state == NULL_STATE)
wtls_machine_destroy(wtls_machine);
}
/*
* Checks whether wtls machines data structure includes a specific machine.
* The machine in question is identified with with source and destination
* address and port.
*/
static WTLSMachine *wtls_machine_find_or_create(WAPEvent *event) {
WTLSMachine *wtls_machine = NULL;
long mid;
WAPAddrTuple *tuple;
tuple = NULL;
mid = -1;
debug("wap.wtls",0, "event->type = %d", event->type);
/* Get the address that this PDU came in from */
switch (event->type) {
case T_Unitdata_Ind:
case T_DUnitdata_Ind:
tuple = event->u.T_Unitdata_Ind.addr_tuple;
break;
case SEC_Create_Request_Req:
case SEC_Terminate_Req:
case SEC_Exception_Req:
case SEC_Create_Res:
case SEC_Exchange_Req:
case SEC_Commit_Req:
case SEC_Unitdata_Req:
tuple = event->u.T_Unitdata_Ind.addr_tuple;
break;
default:
debug("wap.wtls", 0, "WTLS: wtls_machine_find_or_create:"
"unhandled event (1)");
wap_event_dump(event);
return NULL;
}
/* Either the address or the machine id must be available at this point */
gw_assert(tuple != NULL || mid != -1);
/* Look for the machine owning this address */
wtls_machine = wtls_machine_find(tuple, mid);
/* Oh well, we didn't find one. We'll create one instead, provided
it meets certain criteria */
if (wtls_machine == NULL){
switch (event->type){
case SEC_Create_Request_Req:
/* State NULL, case 1 */
debug("wap.wtls",0,"WTLS: received a SEC_Create_Request_Req, and don't know what to do with it...");
/* Create and dispatch a T_Unitdata_Req containing a HelloRequest */
/* And there's no need to do anything else, 'cause we return to state NULL */
break;
case T_Unitdata_Ind:
case T_DUnitdata_Ind:
/* State NULL, case 3 */
/* if (wtls_event_type(event) == Alert_No_Renegotiation) { */
/* Create and dispatch a SEC_Exception_Ind event */
/* debug("wap.wtls",0,"WTLS: received an Alert_no_Renegotiation; just dropped it."); */
/* And there's no need to do anything else, 'cause we return to state NULL */
/* break; */
/* } else */
/* if (event->u.T_Unitdata_Ind == ClientHello) { */
/* State NULL, case 2 */
wtls_machine = wtls_machine_create(tuple);
/* And stick said event into machine, which should push us into state
CREATING after a SEC_Create_Ind */
/* } */
break;
default:
error(0, "WTLS: wtls_machine_find_or_create:"
" unhandled event (2)");
wap_event_dump(event);
break;
}
}
return wtls_machine;
}
static int is_wanted_wtls_machine(void *a, void *b) {
machine_pattern *pat;
WTLSMachine *m;
m = a;
pat = b;
if (m->mid == pat->mid)
return 1;
if (pat->mid != -1)
return 0;
return wap_addr_tuple_same(m->addr_tuple, pat->tuple);
}
static WTLSMachine *wtls_machine_find(WAPAddrTuple *tuple,
long mid) {
machine_pattern pat;
WTLSMachine *m;
pat.tuple = tuple;
pat.mid = mid;
m = gwlist_search(wtls_machines, &pat, is_wanted_wtls_machine);
return m;
}
static WTLSMachine *wtls_machine_create(WAPAddrTuple *tuple) {
WTLSMachine *wtls_machine;
wtls_machine = gw_malloc(sizeof(WTLSMachine));
#define MACHINE(field) field
#define ENUM(name) wtls_machine->name = NULL_STATE;
#define ADDRTUPLE(name) wtls_machine->name = NULL;
#define INTEGER(name) wtls_machine->name = 0;
#define OCTSTR(name) wtls_machine->name = NULL;
#define PDULIST(name) wtls_machine->name = NULL;
#include "wtls_machine-decl.h"
gwlist_append(wtls_machines, wtls_machine);
wtls_machine->mid = counter_increase(wtls_machine_id_counter);
wtls_machine->addr_tuple = wap_addr_tuple_duplicate(tuple);
wtls_machine->handshake_data = octstr_create("");
debug("wap.wtls", 0, "WTLS: Created WTLSMachine %p (%ld)",
(void *) wtls_machine, wtls_machine->mid);
return wtls_machine;
}
/*
* Destroys a WTLSMachine. Assumes it is safe to do so. Assumes it has
* already been deleted from the machines list.
*/
static void wtls_machine_destroy(void * p) {
WTLSMachine *wtls_machine;
wtls_machine = p;
debug("wap.wtls", 0, "WTLS: Destroying WTLSMachine %p (%ld)",
(void *) wtls_machine, wtls_machine->mid);
gwlist_delete_equal(wtls_machines, wtls_machine);
#define MACHINE(field) field
#define ENUM(name) wtls_machine->name = NULL_STATE;
#define ADDRTUPLE(name) wap_addr_tuple_destroy(wtls_machine->name);
#define INTEGER(name) wtls_machine->name = 0;
#define OCTSTR(name) octstr_destroy(wtls_machine->name);
#define PDULIST(name) wtls_machine->name = NULL;
#include "wtls_machine-decl.h"
gw_free(wtls_machine);
}
/*
* Create a TR-Invoke.ind event.
static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data) {
WAPEvent *event;
event = wap_event_create(TR_Invoke_Ind);
event->u.TR_Invoke_Ind.ack_type = sm->u_ack;
event->u.TR_Invoke_Ind.user_data = octstr_duplicate(user_data);
event->u.TR_Invoke_Ind.tcl = sm->tcl;
event->u.TR_Invoke_Ind.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
event->u.TR_Invoke_Ind.handle = sm->mid;
return event;
}
*/
/*
* Create a TR-Result.cnf event.
static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm) {
WAPEvent *event;
event = wap_event_create(TR_Result_Cnf);
event->u.TR_Result_Cnf.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
event->u.TR_Result_Cnf.handle = sm->mid;
return event;
}
*/
/*
* Creates TR-Abort.ind event from a responder state machine.
static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason) {
WAPEvent *event;
event = wap_event_create(TR_Abort_Ind);
event->u.TR_Abort_Ind.abort_code = abort_reason;
event->u.TR_Abort_Ind.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
event->u.TR_Abort_Ind.handle = sm->mid;
return event;
}
*/
static int wtls_machine_has_mid(void *a, void *b) {
WTLSMachine *sm;
long mid;
sm = a;
mid = *(long *) b;
return sm->mid == mid;
}
static WTLSMachine *find_wtls_machine_using_mid(long mid) {
return gwlist_search(wtls_machines, &mid, wtls_machine_has_mid);
}
/* Used for list searches */
static int match_handshake_type(void* item, void* pattern)
{
wtls_Payload* matchingPayload;
int type;
int retrievedType;
matchingPayload = (wtls_Payload*) item;
type = (int) pattern;
retrievedType = octstr_get_char(matchingPayload->data, 0);
if (matchingPayload->type == Handshake_PDU && retrievedType == type)
{
return 1;
}
else
{
return 0;
}
}
static int match_pdu_type(void* item, void* pattern)
{
wtls_Payload* matchingPayload;
int type;
matchingPayload = (wtls_Payload*) item;
type = (int) pattern;
if (matchingPayload->type == type)
{
return 1;
}
else
{
return 0;
}
}
#endif
gateway-1.4.3/wap/wtp_resp_states.def 0000644 0001750 0001750 00000053025 11132672002 016712 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* Macro calls to generate rows of the state table. See the documentation for
* guidance how to use and update these.
*
* Macros have following arguments:
*
* STATE_NAME(name of a wtp machine state)
*
* ROW(the name of the current state,
* the event feeded to wtp machine,
* the condition for the action,
* {the action itself},
* the state wtp machine will transit)
*
* Condition 1 means that the action will be performed unconditionally, action
* {} means that the event in question will be ignored (of course, the state
* of the machine can change).
*
* There are many ROWS generating code for ignoring a certain event (ones hav-
* ing {} as their action). In these cases the event in question is caused by a
* duplicate message and the first one has already changed wtp responder mach-
* ine. In this case ignoring the event is natural.
*
* State tables use the phrase "abort transaction" many times. In this imple-
* mentation this means "clear data structures used for storing transaction
* data". This happens in function resp_event_handle, after included state
* table code.
*
* Commenting the state table is perhaps best done by pointing out how various
* services provided by WTP contribute rows to the state table.
*
* Normal transaction goes as follows (timers excluded):
* - WTP get an invoke pdu from the peer. WTP does TR-Invoke.ind (trans-
* mitting to WSP its PDU) and the state changes to INVOKE_RESP_WAIT
* - WSP does TR-Invoke.res, telling that it has handled the
* indication.
* The state changes to RESULT_WAIT.
* - WSP tells that it has results from the content server, or reply
* pdu to send. It does TR-Result.req. State changes to
* RESULT_RESP_WAIT.
* - WTP gets acknowledgement from the peer. It generates TR_Result.cnf
* and state changes to LISTEN. The transaction is over.
*
* Retransmission until acknowledgement guarantees reliability of the trans-
* action, if the peer stays up. It is implemented by using retransmissions
* controlled by timers and counters. There are two kind of timers, retrans-
* mission and acknowledgement timers. (Actually, there is one timer
* iniatilised with two intervals. But let us keep the language simple).
* These are used in concert with corresponding counters, RCR (retransmission
* counter) and AEC (acknowledgement expiration counter). AEC counts expired
* acknowledgement intervals.
*
* WTP starts an acknowledgement timer when it waits a WSP acknowledgement,
* and retransmission timer when it sends something. So when the acknowledge_
* ment timer expires, the action is to increment AEC, and when the retrans-
* mission timer expires, the action is to resend a packet. (Note, however,
* the chapter concerning user acknowledgement.)
*
* WTP ignores invoke pdus having same tid as the current transaction. This
* quarantees rejection of the duplicates. Note, however, how reliability is
* achieved when WTP is doing tid verification (next chapter).
*
* Tid verification is done if tid validation fails (which happens when the
* message is a duplicate or when tid wrapping-up could confuse the protocol).
* In this case, the state changes to TIDOK_WAIT. WSP is indicated only after
* an acknowledgement is received. After a negative answer (Abort PDU) the
* transaction is teared down. Reliablity is quaranteed by resending, which
* happens when WTP receives a resent invoke pdu, when its state TIDOK_WAIT.
* Abort pdu now means a negative answer to a question "have you a transaction
* having tid included in the tid verification message". So there is no need
* to indicate WSP.
*
* Error handling is mostly done before feeding an event to the state machine.
* However, when a pdu with an illegal header (header WTP does not understand)
* is received, this is a special kind of event, because its handling depends
* of the state. WTP must always send an abort pdu. If a transaction is
* established, it must be teared down. If WSP has been indicated about a
* transaction, WTP must do TR-Abort.ind.
*
* There are two kind of aborts: by the peer, when it sends abort pdu and by the
* wsp, when it does a primitive TR-Abort.req. When WSP does an abort, WTP
* must send an abort pdu to the peer; when WTP receives an abort, WSP must be
* indicated (note, however, the special meaning abort pdu has in tid
* verification; see the relevant chapter).
*
* User acknowledgement means that WTP waits WSP (which in most cases is WTP
* user) acknowledgement, instead of doing it by itself. This means, that if
* user acknowledgement flag is off, WTP sends an ack pdu when acknowledgement
* timer expires.
*
* By Aarno Syvnen for WapIT Ltd.
*/
STATE_NAME(LISTEN)
STATE_NAME(TIDOK_WAIT)
STATE_NAME(INVOKE_RESP_WAIT)
STATE_NAME(RESULT_WAIT)
STATE_NAME(RESULT_RESP_WAIT)
STATE_NAME(WAIT_TIMEOUT_STATE)
ROW(LISTEN,
RcvInvoke,
(event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) &&
wtp_tid_is_valid(event, resp_machine) == ok,
{
resp_machine->u_ack = event->u.RcvInvoke.up_flag;
resp_machine->tcl = event->u.RcvInvoke.tcl;
wsp_event = create_tr_invoke_ind(resp_machine,
event->u.RcvInvoke.user_data);
if (resp_machine->tcl == 1)
wsp_push_client_dispatch_event(wsp_event);
else
wsp_session_dispatch_event(wsp_event);
start_timer_A(resp_machine);
resp_machine->ack_pdu_sent = 0;
},
INVOKE_RESP_WAIT)
/*
* We must here store event fields and wsp indication into the wtp responder
* state machine: if tid is valid, we will continue the transaction without a
* new event.
*/
ROW(LISTEN,
RcvInvoke,
(event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) &&
(wtp_tid_is_valid(event, resp_machine) == fail ||
wtp_tid_is_valid(event, resp_machine) == no_cached_tid),
{
send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid);
resp_machine->u_ack = event->u.RcvInvoke.up_flag;
resp_machine->tcl = event->u.RcvInvoke.tcl;
resp_machine->invoke_indication = create_tr_invoke_ind(resp_machine,
event->u.RcvInvoke.user_data);
debug("wap.wtp", 0, "WTP_STATE: generating invoke indication, tid being"
"invalid");
},
TIDOK_WAIT)
/*
* Do not change state when class 0 message is received.
*/
ROW(LISTEN,
RcvInvoke,
event->u.RcvInvoke.tcl == 0,
{
wsp_event = create_tr_invoke_ind(resp_machine,
event->u.RcvInvoke.user_data);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
/*
* No user indication here: transaction is not yet started.
*/
ROW(LISTEN,
RcvErrorPDU,
1,
{
send_abort(resp_machine, PROVIDER, PROTOERR);
},
LISTEN)
/*
* Need to control SAR incomplete packets
*/
ROW(LISTEN,
TimerTO_W,
1,
{},
LISTEN)
/*
* We must cache the newly accepted tid item, otherwise every tid after a
* suspected one will be validated. We use wsp event stored by the responder
* machine.
*/
ROW(TIDOK_WAIT,
RcvAck,
(resp_machine->tcl == 2 || resp_machine->tcl == 1) &&
event->u.RcvAck.tid_ok == 1,
{
wsp_event = wap_event_duplicate(resp_machine->invoke_indication);
if (resp_machine->tcl == 1)
wsp_push_client_dispatch_event(wsp_event);
else
wsp_session_dispatch_event(wsp_event);
wtp_tid_set_by_machine(resp_machine, event->u.RcvAck.tid);
start_timer_A(resp_machine);
resp_machine->ack_pdu_sent = 0;
},
INVOKE_RESP_WAIT)
/*
* When we get a negative answer to tid verification, we just abort trans-
* action. Because wtp machines are destroyed when their state return to
* LISTEN and because no transaction is yet started, there is no need to do
* anything here.
*/
ROW(TIDOK_WAIT,
RcvAbort,
1,
{ },
LISTEN)
ROW(TIDOK_WAIT,
RcvInvoke,
event->u.RcvInvoke.rid == 0,
{ },
TIDOK_WAIT)
/*
* Because the phone sends invoke again, previous ack was dropped by the
* bearer.
*/
ROW(TIDOK_WAIT,
RcvInvoke,
event->u.RcvInvoke.rid == 1,
{
send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid);
},
TIDOK_WAIT)
/*
* No need for wsp indication: the transaction is not yet started.
*/
ROW(TIDOK_WAIT,
RcvErrorPDU,
1,
{
send_abort(resp_machine, PROVIDER, PROTOERR);
},
LISTEN)
ROW(INVOKE_RESP_WAIT,
RcvInvoke,
1,
{ },
INVOKE_RESP_WAIT)
ROW(INVOKE_RESP_WAIT,
TR_Invoke_Res,
resp_machine->tcl == 2,
{
start_timer_A(resp_machine);
resp_machine->aec = 0;
},
RESULT_WAIT)
ROW(INVOKE_RESP_WAIT,
TR_Invoke_Res,
resp_machine->tcl == 1,
{
send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
start_timer_W(resp_machine);
},
WAIT_TIMEOUT_STATE)
ROW(INVOKE_RESP_WAIT,
RcvAbort,
1,
{
wsp_event = create_tr_abort_ind(resp_machine,
event->u.RcvAbort.abort_reason);
if (resp_machine->tcl == 1)
wsp_push_client_dispatch_event(wsp_event);
else
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
ROW(INVOKE_RESP_WAIT,
TR_Abort_Req,
1,
{
send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
},
LISTEN)
/*
* non-SARed
*/
ROW(INVOKE_RESP_WAIT,
TR_Result_Req,
resp_machine->sar == NULL,
{
WAPEvent *result;
resp_machine->rcr = 0;
start_timer_R(resp_machine);
wap_event_destroy(resp_machine->result);
resp_machine->rid = 0;
result = wtp_pack_result(resp_machine, event);
resp_machine->result = wap_event_duplicate(result);
dispatch_to_wdp(result);
resp_machine->rid = 1;
},
RESULT_RESP_WAIT)
/*
* SARed
*/
ROW(INVOKE_RESP_WAIT,
TR_Result_Req,
resp_machine->sar != NULL,
{
resp_machine->rcr = 0;
start_timer_R(resp_machine);
wap_event_destroy(resp_machine->result);
resp_machine->rid = 0;
begin_sar_result(resp_machine, event);
},
RESULT_RESP_WAIT)
/*
* Conditions below do not correspond wholly ones found from the spec. (If
* they does, user acknowledgement flag would never be used by the protocol,
* which cannot be the original intention.)
* User acknowledgement flag is used following way: if it is on, WTP does not
* send an acknowledgement (user acknowledgement in form of TR-Invoke.res or
* TR-Result.req instead of provider acknowledgement is awaited); if it is
* off, WTP does this. IMHO, specs support this exegesis: there is condition
* Uack == False && class == 2 with action send ack pdu. In addition, WTP
* 8.3.1 says " When [user acknowledgement] is enabled WTP provider does not
* respond to a received message until after WTP user has confirmed the
* indication service primitive by issuing the response primitive".
*
* BTW: CR correcting this shall appear soonish.
*/
ROW(INVOKE_RESP_WAIT,
TimerTO_A,
resp_machine->aec < AEC_MAX && resp_machine->u_ack == 1,
{
++resp_machine->aec;
start_timer_A(resp_machine);
},
INVOKE_RESP_WAIT)
ROW(INVOKE_RESP_WAIT,
TimerTO_A,
(resp_machine->aec < AEC_MAX && resp_machine->u_ack == 0),
{
++resp_machine->aec;
start_timer_A(resp_machine);
send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
if (resp_machine->ack_pdu_sent == 0)
resp_machine->ack_pdu_sent = 1;
},
INVOKE_RESP_WAIT)
/*
* When a transaction is aborted, WSP must surely know this. One of corrections
* in MOT_WTP_CR_01. What to do when a counter reaches its maximum value dep-
* ends on whether we have opened the connection or not. In previous case, we
* must go to the state WAIT_TIMEOUT_STATE, for instance to prevent bad incarn-
* ations.
*/
ROW(INVOKE_RESP_WAIT,
TimerTO_A,
resp_machine->aec == AEC_MAX && resp_machine->tcl == 2,
{
send_abort(resp_machine, PROVIDER, NORESPONSE);
wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
ROW(INVOKE_RESP_WAIT,
TimerTO_A,
resp_machine->aec == AEC_MAX && resp_machine->tcl == 1,
{
start_timer_W(resp_machine);
},
WAIT_TIMEOUT_STATE)
ROW(INVOKE_RESP_WAIT,
RcvErrorPDU,
1,
{
send_abort(resp_machine, PROVIDER, PROTOERR);
wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
if (resp_machine->tcl == 1)
wsp_push_client_dispatch_event(wsp_event);
else
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
/*
* Non-SARed
*/
ROW(RESULT_WAIT,
TR_Result_Req,
resp_machine->sar == NULL,
{
WAPEvent *result;
resp_machine->rcr = 0;
start_timer_R(resp_machine);
wap_event_destroy(resp_machine->result);
resp_machine->rid = 0;
result = wtp_pack_result(resp_machine, event);
resp_machine->result = wap_event_duplicate(result);
dispatch_to_wdp(result);
resp_machine->rid = 1;
},
RESULT_RESP_WAIT)
/*
* SARed
*/
ROW(RESULT_WAIT,
TR_Result_Req,
(resp_machine->sar != NULL) && ((octstr_len(event->u.TR_Result_Req.user_data)-1)/SAR_SEGM_SIZE < 255),
{
resp_machine->rcr = 0;
start_timer_R(resp_machine);
wap_event_destroy(resp_machine->result);
resp_machine->rid = 0;
begin_sar_result(resp_machine, event);
},
RESULT_RESP_WAIT)
ROW(RESULT_WAIT,
TR_Result_Req,
(resp_machine->sar != NULL) && ((octstr_len(event->u.TR_Result_Req.user_data)-1)/SAR_SEGM_SIZE >= 255),
{
send_abort(resp_machine, PROVIDER, NOTIMPLEMENTEDESAR);
wsp_event = create_tr_abort_ind(resp_machine, NOTIMPLEMENTEDESAR);
wsp_session_dispatch_event(wsp_event);
wap_event_destroy(resp_machine->result);
},
LISTEN)
ROW(RESULT_WAIT,
RcvAbort,
1,
{
wsp_event = create_tr_abort_ind(resp_machine,
event->u.RcvAbort.abort_reason);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
ROW(RESULT_WAIT,
RcvInvoke,
event->u.RcvInvoke.rid == 0,
{ },
RESULT_WAIT)
ROW(RESULT_WAIT,
RcvInvoke,
event->u.RcvInvoke.rid == 1 && resp_machine->ack_pdu_sent == 0,
{ },
RESULT_WAIT)
ROW(RESULT_WAIT,
RcvInvoke,
event->u.RcvInvoke.rid == 1 && resp_machine->ack_pdu_sent == 1,
{
send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
},
RESULT_WAIT)
ROW(RESULT_WAIT,
TR_Abort_Req,
1,
{
send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
},
LISTEN)
ROW(RESULT_WAIT,
RcvErrorPDU,
1,
{
send_abort(resp_machine, PROVIDER, PROTOERR);
wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
/*
* This state follows two possible ones: INVOKE_RESP_WAIT & TR-Invoke.res and
* INVOKE_RESP_WAIT & TimerTO_A & Class == 2 & Uack == FALSE. Contrary what
* spec says, in first case we are now sending first time. We must, too, abort
* after AEC_MAX timer periods.
*/
ROW(RESULT_WAIT,
TimerTO_A,
resp_machine->aec < AEC_MAX,
{
start_timer_A(resp_machine);
send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
if (resp_machine->ack_pdu_sent == 0)
resp_machine->ack_pdu_sent = 1;
resp_machine->aec++;
},
RESULT_WAIT)
ROW(RESULT_WAIT,
TimerTO_A,
resp_machine->aec == AEC_MAX,
{
send_abort(resp_machine, PROVIDER, NORESPONSE);
wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
/*
* A duplicate ack(tidok) caused by a heavy load (the original changed state
* from TIDOK_WAIT). This implements CR-Nokia-WTP-20-March-2000/2.
*/
ROW(RESULT_WAIT,
RcvAck,
event->u.RcvAck.tid_ok,
{},
RESULT_WAIT)
/*
* Non-SARed
*/
ROW(RESULT_RESP_WAIT,
RcvAck,
resp_machine->sar == NULL || event->u.RcvAck.psn == resp_machine->sar->nsegm,
{
wsp_event = create_tr_result_cnf(resp_machine);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
/*
* SARed
*/
ROW(RESULT_RESP_WAIT,
RcvAck,
resp_machine->sar != NULL && event->u.RcvAck.psn != resp_machine->sar->nsegm,
{
continue_sar_result(resp_machine, event);
},
RESULT_RESP_WAIT)
ROW(RESULT_RESP_WAIT,
RcvNegativeAck,
resp_machine->sar != NULL,
{
resend_sar_result(resp_machine, event);
},
RESULT_RESP_WAIT)
/*
* Specs does not tell what to do, when wtp responder receives invoke pdu and
* its state is RESULT_RESP_WAIT. This can happen, however: event causing the
* transition RESULT_WAIT -> RESULT_RESP_WAIT is TR-Result.req, an internal
* responder event.
*/
ROW(RESULT_RESP_WAIT,
RcvInvoke,
1,
{ },
RESULT_RESP_WAIT)
ROW(RESULT_RESP_WAIT,
RcvAbort,
1,
{
wsp_event = create_tr_abort_ind(resp_machine,
event->u.RcvAbort.abort_reason);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
ROW(RESULT_RESP_WAIT,
TR_Abort_Req,
1,
{
send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
},
LISTEN)
ROW(RESULT_RESP_WAIT,
TimerTO_R,
resp_machine->rcr < MAX_RCR,
{
WAPEvent *resend;
start_timer_R(resp_machine);
resend = wap_event_duplicate(resp_machine->result);
wtp_pack_set_rid(resend, resp_machine->rid);
dispatch_to_wdp(resend);
++resp_machine->rcr;
},
RESULT_RESP_WAIT)
ROW(RESULT_RESP_WAIT,
TimerTO_R,
resp_machine->rcr == MAX_RCR,
{
send_abort(resp_machine, PROVIDER, NORESPONSE);
wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
ROW(RESULT_RESP_WAIT,
RcvErrorPDU,
1,
{
send_abort(resp_machine, PROVIDER, PROTOERR);
wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
wsp_session_dispatch_event(wsp_event);
},
LISTEN)
ROW(WAIT_TIMEOUT_STATE,
RcvInvoke,
event->u.RcvInvoke.rid == 0,
{ },
WAIT_TIMEOUT_STATE)
ROW(WAIT_TIMEOUT_STATE,
RcvInvoke,
event->u.RcvInvoke.rid == 1,
{
send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
},
WAIT_TIMEOUT_STATE)
ROW(WAIT_TIMEOUT_STATE,
RcvErrorPDU,
1,
{
send_abort(resp_machine, PROVIDER, PROTOERR);
wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
wsp_push_client_dispatch_event(wsp_event);
},
LISTEN)
ROW(WAIT_TIMEOUT_STATE,
RcvAbort,
1,
{
wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
wsp_push_client_dispatch_event(wsp_event);
},
LISTEN)
/*
* Waiting to prevent premature incarnations.
*/
ROW(WAIT_TIMEOUT_STATE,
TimerTO_W,
1,
{
wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
wsp_push_client_dispatch_event(wsp_event);
},
LISTEN)
ROW(WAIT_TIMEOUT_STATE,
TR_Abort_Req,
1,
{
send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
},
LISTEN)
#undef ROW
#undef STATE_NAME
gateway-1.4.3/wap/wsp_strings.def 0000644 0001750 0001750 00000066562 11132672002 016060 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/**** Preprocessor magic ****/
/* String table with entries starting at 0 and numbered upwards. */
#if !defined(LINEAR)
#error "Required macro LINEAR is missing."
#endif
/* Entry in a LINEAR table. Default is to do nothing for it. */
#if !defined(STRING)
#define STRING
#endif
/* String table where entries have assigned numbers. Multiple
* entries can have the same number (the first listed entry is used
* when looking up by number). */
#if !defined(NUMBERED)
#define NUMBERED LINEAR
#endif
/* Entry in a NUMBERED table */
#if !defined(ASSIGN)
#define ASSIGN(string, number) STRING(string)
#endif
/* Entry in a versioned NUMBERED table */
#if !defined(VASSIGN)
#define VASSIGN(version, string, number) VSTRING(version, string)
#endif
/* Just like LINEAR, but an enumerated type name##_enum is defined for
* the entries. */
#if !defined(NAMED)
#define NAMED LINEAR
#endif
/* Entry in a NAMED table */
#if !defined(NSTRING)
#define NSTRING(string, name) STRING(string)
#endif
/* Entry in a versioned NAMED table */
#if !defined(VNSTRING)
#define VNSTRING(version, string, name) VSTRING(version, string)
#endif
/**** End of preprocessor magic. Tables start here. ****/
/* Table 39. Header Field Name Assignments. Note that headers Accept-Charset, Accept-Encoding,
* Cache-Control and Content-Range are defined twice. First ones should be used only for com-
* pability reasons. */
NAMED(header,
VNSTRING(WSP_1_1, "Accept", WSP_HEADER_ACCEPT)
VNSTRING(WSP_1_1, "Accept-Charset", WSP_HEADER_ACCEPT_CHARSET)
VNSTRING(WSP_1_1, "Accept-Encoding", WSP_HEADER_ACCEPT_ENCODING)
VNSTRING(WSP_1_1, "Accept-Language", WSP_HEADER_ACCEPT_LANGUAGE)
VNSTRING(WSP_1_1, "Accept-Ranges", WSP_HEADER_ACCEPT_RANGES)
VNSTRING(WSP_1_1, "Age", WSP_HEADER_AGE)
VNSTRING(WSP_1_1, "Allow", WSP_HEADER_ALLOW)
VNSTRING(WSP_1_1, "Authorization", WSP_HEADER_AUTHORIZATION)
VNSTRING(WSP_1_1, "Cache-Control", WSP_HEADER_CACHE_CONTROL)
VNSTRING(WSP_1_1, "Connection", WSP_HEADER_CONNECTION)
VNSTRING(WSP_1_1, "Content-Base", WSP_HEADER_CONTENT_BASE)
VNSTRING(WSP_1_1, "Content-Encoding", WSP_HEADER_CONTENT_ENCODING)
VNSTRING(WSP_1_1, "Content-Language", WSP_HEADER_CONTENT_LANGUAGE)
VNSTRING(WSP_1_1, "Content-Length", WSP_HEADER_CONTENT_LENGTH)
VNSTRING(WSP_1_1, "Content-Location", WSP_HEADER_CONTENT_LOCATION)
VNSTRING(WSP_1_1, "Content-MD5", WSP_HEADER_CONTENT_MD5)
VNSTRING(WSP_1_1, "Content-Range", WSP_HEADER_CONTENT_RANGE)
VNSTRING(WSP_1_1, "Content-Type", WSP_HEADER_CONTENT_TYPE)
VNSTRING(WSP_1_1, "Date", WSP_HEADER_DATE)
VNSTRING(WSP_1_1, "Etag", WSP_HEADER_ETAG)
VNSTRING(WSP_1_1, "Expires", WSP_HEADER_EXPIRES)
VNSTRING(WSP_1_1, "From", WSP_HEADER_FROM)
VNSTRING(WSP_1_1, "Host", WSP_HEADER_HOST)
VNSTRING(WSP_1_1, "If-Modified-Since", WSP_HEADER_IF_MODIFIED_SINCE)
VNSTRING(WSP_1_1, "If-Match", WSP_HEADER_IF_MATCH)
VNSTRING(WSP_1_1, "If-None-Match", WSP_HEADER_IF_NONE_MATCH)
VNSTRING(WSP_1_1, "If-Range", WSP_HEADER_IF_RANGE)
VNSTRING(WSP_1_1, "If-Unmodified-Since", WSP_HEADER_IF_UNMODIFIED_SINCE)
VNSTRING(WSP_1_1, "Location", WSP_HEADER_LOCATION)
VNSTRING(WSP_1_1, "Last-Modified", WSP_HEADER_LAST_MODIFIED)
VNSTRING(WSP_1_1, "Max-Forwards", WSP_HEADER_MAX_FORWARDS)
VNSTRING(WSP_1_1, "Pragma", WSP_HEADER_PRAGMA)
VNSTRING(WSP_1_1, "Proxy-Authenticate", WSP_HEADER_PROXY_AUTHENTICATE)
VNSTRING(WSP_1_1, "Proxy-Authorization", WSP_HEADER_PROXY_AUTHORIZATION)
VNSTRING(WSP_1_1, "Public", WSP_HEADER_PUBLIC)
VNSTRING(WSP_1_1, "Range", WSP_HEADER_RANGE)
VNSTRING(WSP_1_1, "Referer", WSP_HEADER_REFERER)
VNSTRING(WSP_1_1, "Retry-After", WSP_HEADER_RETRY_AFTER)
VNSTRING(WSP_1_1, "Server", WSP_HEADER_SERVER)
VNSTRING(WSP_1_1, "Transfer-Encoding", WSP_HEADER_TRANSFER_ENCODING)
VNSTRING(WSP_1_1, "Upgrade", WSP_HEADER_UPGRADE)
VNSTRING(WSP_1_1, "User-Agent", WSP_HEADER_USER_AGENT)
VNSTRING(WSP_1_1, "Vary", WSP_HEADER_VARY)
VNSTRING(WSP_1_1, "Via", WSP_HEADER_VIA)
VNSTRING(WSP_1_1, "Warning", WSP_HEADER_WARNING)
VNSTRING(WSP_1_1, "WWW-Authenticate", WSP_HEADER_WWW_AUTHENTICATE)
VNSTRING(WSP_1_1, "Content-Disposition", WSP_HEADER_CONTENT_DISPOSITION)
VNSTRING(WSP_1_2, "X-Wap-Application-Id", WSP_HEADER_X_WAP_APPLICATION_ID)
VNSTRING(WSP_1_2, "X-Wap-Content-URI", WSP_HEADER_X_WAP_CONTENT_URI)
VNSTRING(WSP_1_2, "X-Wap-Initiator-URI", WSP_HEADER_X_WAP_INITIATOR_URI)
VNSTRING(WSP_1_2, "Accept-Application", WSP_HEADER_ACCEPT_APPLICATION)
VNSTRING(WSP_1_2, "Bearer-Indication", WSP_HEADER_BEARER_INDICATION)
VNSTRING(WSP_1_2, "Push-Flag", WSP_HEADER_PUSH_FLAG)
VNSTRING(WSP_1_2, "Profile", WSP_HEADER_PROFILE)
VNSTRING(WSP_1_2, "Profile-Diff", WSP_HEADER_PROFILE_DIFF)
VNSTRING(WSP_1_2, "Profile-Warning", WSP_HEADER_PROFILE_WARNING)
VNSTRING(WSP_1_3, "Expect", WSP_HEADER_EXPECT)
VNSTRING(WSP_1_3, "TE", WSP_HEADER_TE)
VNSTRING(WSP_1_3, "Trailer", WSP_HEADER_TRAILER)
VNSTRING(WSP_1_3, "Accept-Charset", WSP_HEADER_ACCEPT_CHARSET_V13)
VNSTRING(WSP_1_3, "Accept-Encoding", WSP_HEADER_ACCEPT_ENCODING_V13)
VNSTRING(WSP_1_3, "Cache-Control", WSP_HEADER_CACHE_CONTROL_V13)
VNSTRING(WSP_1_3, "Content-Range", WSP_HEADER_CONTENT_RANGE_V13)
VNSTRING(WSP_1_3, "X-WAP-Tod", WSP_HEADER_X_WAP_TOD)
VNSTRING(WSP_1_3, "Content-ID", WSP_HEADER_CONTENT_ID)
VNSTRING(WSP_1_3, "Set-Cookie", WSP_HEADER_SET_COOKIE)
VNSTRING(WSP_1_3, "Cookie", WSP_HEADER_COOKIE)
VNSTRING(WSP_1_3, "Encoding-Version", WSP_HEADER_ENCODING_VERSION)
VNSTRING(WSP_1_4, "Profile-Warning", WSP_HEADER_PROFILE_WARNING_V14)
VNSTRING(WSP_1_4, "Content-Disposition", WSP_HEADER_CONTENT_DISPOSITION_V14)
VNSTRING(WSP_1_4, "X-WAP-Security", WSP_HEADER_X_WAP_SECURITY)
VNSTRING(WSP_1_4, "Cache-Control", WSP_HEADER_CACHE_CONTROL_V14)
VNSTRING(WSP_1_5, "X-Wap-Loc-Invocation", WSP_HEADER_X_WAP_LOC_INVOCATION)
VNSTRING(WSP_1_5, "X-Wap-Loc-Delivery", WSP_HEADER_X_WAP_LOC_DELIVERY)
)
/* Table 40. Well Known WSP Content Type Codes Assignments.
* These have been defined by WINA,
* see http://www.wapforum.org/wina/wsp-content-type.htm
* Now they are maintained by OMNA, see URL
*
* http://www.openmobilealliance.org/tech/omna/index.htm (depricated)
* http://www.openmobilealliance.org/Technical/omna/omna-wsp-content-type.aspx
*/
LINEAR(content_type,
VSTRING(WSP_1_1, "*/*")
VSTRING(WSP_1_1, "text/*")
VSTRING(WSP_1_1, "text/html")
VSTRING(WSP_1_1, "text/plain")
VSTRING(WSP_1_1, "text/x-hdml")
VSTRING(WSP_1_1, "text/x-ttml")
VSTRING(WSP_1_1, "text/x-vCalendar")
VSTRING(WSP_1_1, "text/x-vCard")
VSTRING(WSP_1_1, "text/vnd.wap.wml")
VSTRING(WSP_1_1, "text/vnd.wap.wmlscript")
VSTRING(WSP_1_1, "application/vnd.wap.catc")
VSTRING(WSP_1_1, "multipart/*")
VSTRING(WSP_1_1, "multipart/mixed")
VSTRING(WSP_1_1, "multipart/form-data")
VSTRING(WSP_1_1, "multipart/byteranges")
VSTRING(WSP_1_1, "multipart/alternative")
VSTRING(WSP_1_1, "application/*")
VSTRING(WSP_1_1, "application/java-vm")
VSTRING(WSP_1_1, "application/x-www-form-urlencoded")
VSTRING(WSP_1_1, "application/x-hdmlc")
VSTRING(WSP_1_1, "application/vnd.wap.wmlc")
VSTRING(WSP_1_1, "application/vnd.wap.wmlscriptc")
VSTRING(WSP_1_1, "application/vnd.wap.wsic")
VSTRING(WSP_1_1, "application/vnd.wap.uaprof")
VSTRING(WSP_1_1, "application/vnd.wap.wtls-ca-certificate")
VSTRING(WSP_1_1, "application/vnd.wap.wtls-user-certificate")
VSTRING(WSP_1_1, "application/x-x509-ca-cert")
VSTRING(WSP_1_1, "application/x-x509-user-cert")
VSTRING(WSP_1_1, "image/*")
VSTRING(WSP_1_1, "image/gif")
VSTRING(WSP_1_1, "image/jpeg")
VSTRING(WSP_1_1, "image/tiff")
VSTRING(WSP_1_1, "image/png")
VSTRING(WSP_1_1, "image/vnd.wap.wbmp")
VSTRING(WSP_1_1, "application/vnd.wap.multipart.*")
VSTRING(WSP_1_1, "application/vnd.wap.multipart.mixed")
VSTRING(WSP_1_1, "application/vnd.wap.multipart.form-data")
VSTRING(WSP_1_1, "application/vnd.wap.multipart.byteranges")
VSTRING(WSP_1_1, "application/vnd.wap.multipart.alternative")
VSTRING(WSP_1_1, "application/xml")
VSTRING(WSP_1_1, "text/xml")
VSTRING(WSP_1_1, "application/vnd.wap.wbxml")
VSTRING(WSP_1_1, "application/x-x968-cross-cert")
VSTRING(WSP_1_1, "application/x-x968-ca-cert")
VSTRING(WSP_1_1, "application/x-x968-user-cert")
VSTRING(WSP_1_1, "text/vnd.wap.si")
VSTRING(WSP_1_2, "application/vnd.wap.sic")
VSTRING(WSP_1_2, "text/vnd.wap.sl")
VSTRING(WSP_1_2, "application/vnd.wap.slc")
VSTRING(WSP_1_2, "text/vnd.wap.co")
VSTRING(WSP_1_2, "application/vnd.wap.coc")
VSTRING(WSP_1_2, "application/vnd.wap.multipart.related")
VSTRING(WSP_1_2, "application/vnd.wap.sia")
VSTRING(WSP_1_3, "text/vnd.wap.connectivity-xml")
VSTRING(WSP_1_3, "application/vnd.wap.connectivity-wbxml")
VSTRING(WSP_1_4, "application/pkcs7-mime")
VSTRING(WSP_1_4, "application/vnd.wap.hashed-certificate")
VSTRING(WSP_1_4, "application/vnd.wap.signed-certificate")
VSTRING(WSP_1_4, "application/vnd.wap.cert-response")
VSTRING(WSP_1_4, "application/xhtml+xml")
VSTRING(WSP_1_4, "application/wml+xml")
VSTRING(WSP_1_4, "text/css")
VSTRING(WSP_1_4, "application/vnd.wap.mms-message")
VSTRING(WSP_1_4, "application/vnd.wap.rollover-certificate")
VSTRING(WSP_1_5, "application/vnd.wap.locc+wbxml")
VSTRING(WSP_1_5, "application/vnd.wap.loc+xml")
VSTRING(WSP_1_5, "application/vnd.syncml.dm+wbxml")
VSTRING(WSP_1_5, "application/vnd.syncml.dm+xml")
VSTRING(WSP_1_5, "application/vnd.syncml.notification")
VSTRING(WSP_1_5, "application/vnd.wap.xhtml+xml")
VSTRING(WSP_1_5, "application/vnd.wv.csp.cir")
VSTRING(WSP_1_5, "application/vnd.oma.dd+xml")
VSTRING(WSP_1_5, "application/vnd.oma.drm.message")
VSTRING(WSP_1_5, "application/vnd.oma.drm.content")
VSTRING(WSP_1_5, "application/vnd.oma.drm.rights+xml")
VSTRING(WSP_1_5, "application/vnd.oma.drm.rights+wbxml")
VSTRING(WSP_1_5, "application/vnd.wv.csp+xml")
VSTRING(WSP_1_5, "application/vnd.wv.csp+wbxml")
VSTRING(WSP_1_5, "application/vnd.syncml.ds.notification")
VSTRING(WSP_1_6, "audio/*")
VSTRING(WSP_1_6, "video/*")
VSTRING(WSP_1_6, "application/vnd.oma.dd2+xml")
VSTRING(WSP_1_6, "application/mikey")
)
/* Registered WSP Content Type Codes Assignments.
* Now they are maintained by OMNA, see URL
*
* http://www.openmobilealliance.org/tech/omna/index.htm (depricated)
* http://www.openmobilealliance.org/Technical/omna/omna-wsp-content-type.aspx
*/
NUMBERED(content_type_registered,
ASSIGN("application/vnd.uplanet.cacheop-wbxml", 0x0201)
ASSIGN("application/vnd.uplanet.signal", 0x0202)
ASSIGN("application/vnd.uplanet.alert-wbxml", 0x0203)
ASSIGN("application/vnd.uplanet.list-wbxml", 0x0204)
ASSIGN("application/vnd.uplanet.listcmd-wbxml", 0x0205)
ASSIGN("application/vnd.uplanet.channel-wbxml", 0x0206)
ASSIGN("application/vnd.uplanet.provisioning-status-uri", 0x0207)
ASSIGN("x-wap.multipart/vnd.uplanet.header-set", 0x0208)
ASSIGN("application/vnd.uplanet.bearer-choice-wbxml", 0x0209)
ASSIGN("application/vnd.phonecom.mmc-wbxml", 0x020A)
ASSIGN("application/vnd.nokia.syncset+wbxml", 0x020B)
ASSIGN("image/x-up-wpng", 0x020C)
ASSIGN("application/iota.mmc-wbxml", 0x0300)
ASSIGN("application/iota.mmc-xml", 0x0301)
ASSIGN("application/vnd.syncml+xml", 0x0302)
ASSIGN("application/vnd.syncml+wbxml", 0x0303)
ASSIGN("text/vnd.wap.emn+xml", 0x0304)
ASSIGN("text/calendar", 0x0305)
ASSIGN("application/vnd.omads-email+xml", 0x0306)
ASSIGN("application/vnd.omads-file+xml", 0x0307)
ASSIGN("application/vnd.omads-folder+xml", 0x0308)
ASSIGN("text/directory;profile=vCard", 0x0309)
ASSIGN("application/vnd.wap.emn+wbxml", 0x030A)
ASSIGN("application/vnd.nokia.ipdc-purchase-response", 0x030B)
ASSIGN("application/vnd.motorola.screen3+xml", 0x030C)
ASSIGN("application/vnd.motorola.screen3+gzip", 0x030D)
ASSIGN("application/vnd.cmcc.setting+wbxml", 0x030E)
ASSIGN("application/vnd.cmcc.bombing+wbxml", 0x030F)
ASSIGN("application/vnd.docomo.pf", 0x0310)
ASSIGN("application/vnd.docomo.ub", 0x0311)
ASSIGN("application/vnd.omaloc-supl-init", 0x0312)
ASSIGN("application/vnd.oma.group-usage-list+xml", 0x0313)
ASSIGN("application/oma-directory+xml", 0x0314)
ASSIGN("application/vnd.docomo.pf2", 0x0315)
)
/* Table 42, Character Set Assignment (partial) */
/* The full list is at
* ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
* but the WSP standard lists these values explicitly.
*/
NUMBERED(charset,
ASSIGN("big5", 2026)
ASSIGN("iso-10646-ucs-2", 1000)
ASSIGN("iso-8859-1", 4)
ASSIGN("iso-8859-2", 5)
ASSIGN("iso-8859-3", 6)
ASSIGN("iso-8859-4", 7)
ASSIGN("iso-8859-5", 8)
ASSIGN("iso-8859-6", 9)
ASSIGN("iso-8859-7", 10)
ASSIGN("iso-8859-8", 11)
ASSIGN("iso-8859-9", 12)
ASSIGN("shift_JIS", 17)
ASSIGN("us-ascii", 3)
ASSIGN("utf-8", 106)
ASSIGN("utf-16", 1015)
)
/* Table 38, Well-Known Parameter Assignments
* Now defined by OMNA, see
* http://www.openmobilealliance.org/tech/omna/omna-wsp-header-param.htm
*/
NUMBERED(parameter,
VASSIGN(WSP_1_1, "q", 0)
VASSIGN(WSP_1_1, "charset", 1)
VASSIGN(WSP_1_1, "level", 2)
VASSIGN(WSP_1_1, "type", 3)
VASSIGN(WSP_1_1, "uaprof", 4)
VASSIGN(WSP_1_1, "name", 5)
VASSIGN(WSP_1_1, "filename", 6)
VASSIGN(WSP_1_1, "differences", 7)
VASSIGN(WSP_1_1, "padding", 8)
VASSIGN(WSP_1_2, "type", 9)
VASSIGN(WSP_1_2, "start", 10)
VASSIGN(WSP_1_2, "start-info", 11)
VASSIGN(WSP_1_3, "comment", 12)
VASSIGN(WSP_1_3, "domain", 13)
VASSIGN(WSP_1_3, "max-age", 14)
VASSIGN(WSP_1_3, "path", 15)
VASSIGN(WSP_1_3, "secure", 16)
VASSIGN(WSP_1_4, "sec", 17)
VASSIGN(WSP_1_4, "mac", 18)
VASSIGN(WSP_1_4, "creation-date", 19)
VASSIGN(WSP_1_4, "modification-date", 20)
VASSIGN(WSP_1_4, "read-date", 21)
VASSIGN(WSP_1_4, "size", 22)
VASSIGN(WSP_1_4, "name", 23)
VASSIGN(WSP_1_4, "filename", 24)
VASSIGN(WSP_1_4, "start", 25)
VASSIGN(WSP_1_4, "start-info", 26)
VASSIGN(WSP_1_4, "comment", 27)
VASSIGN(WSP_1_4, "domain", 28)
VASSIGN(WSP_1_4, "path", 29)
)
/* 8.4.2.18, Content encoding field */
LINEAR(encoding,
STRING("gzip")
STRING("compress")
STRING("deflate")
)
/* 8.4.2.11, Accept ranges field */
LINEAR(ranges,
STRING("none")
STRING("bytes")
)
/* 8.4.2.15, Cache-control field */
NAMED(cache_control,
NSTRING("no-cache", WSP_CACHE_CONTROL_NO_CACHE)
NSTRING("no-store", WSP_CACHE_CONTROL_NO_STORE)
NSTRING("max-age", WSP_CACHE_CONTROL_MAX_AGE)
NSTRING("max-stale", WSP_CACHE_CONTROL_MAX_STALE)
NSTRING("min-fresh", WSP_CACHE_CONTROL_MIN_FRESH)
NSTRING("only-if-cached", WSP_CACHE_CONTROL_ONLY_IF_CACHED)
NSTRING("public", WSP_CACHE_CONTROL_PUBLIC)
NSTRING("private", WSP_CACHE_CONTROL_PRIVATE)
NSTRING("no-transform", WSP_CACHE_CONTROL_NO_TRANSFORM)
NSTRING("must-revalidate", WSP_CACHE_CONTROL_MUST_REVALIDATE)
NSTRING("proxy-revalidate", WSP_CACHE_CONTROL_PROXY_REVALIDATE)
NSTRING("s-maxage", WSP_CACHE_CONTROL_S_MAXAGE)
)
/* 8.4.2.53, Content-disposition field */
LINEAR(disposition,
STRING("form-data")
STRING("attachment")
STRING("inline")
)
/* Table 41, ISO 639 Language Assignments */
/* For some reason this table was incomplete in the spec. The languages
* were listed, but not their abbreviations. */
NUMBERED(language,
ASSIGN("*", 0) /* Special any-language value */
ASSIGN("aa", 0x01) /* Afar */
ASSIGN("ab", 0x02) /* Abkhazian */
ASSIGN("af", 0x03) /* Afrikaans */
ASSIGN("am", 0x04) /* Amharic */
ASSIGN("ar", 0x05) /* Arabic */
ASSIGN("as", 0x06) /* Assamese */
ASSIGN("ay", 0x07) /* Aymara */
ASSIGN("az", 0x08) /* Azerbaijani */
ASSIGN("ba", 0x09) /* Bashkir */
ASSIGN("be", 0x0a) /* Byelorussian */
ASSIGN("bg", 0x0b) /* Bulgarian */
ASSIGN("bh", 0x0c) /* Bihari */
ASSIGN("bi", 0x0d) /* Bislama */
ASSIGN("bn", 0x0e) /* Bengali; Bangla */
ASSIGN("bo", 0x0f) /* Tibetan */
ASSIGN("br", 0x10) /* Breton */
ASSIGN("ca", 0x11) /* Catalan */
ASSIGN("co", 0x12) /* Corsican */
ASSIGN("cs", 0x13) /* Czech */
ASSIGN("cy", 0x14) /* Welsh */
ASSIGN("da", 0x15) /* Danish */
ASSIGN("de", 0x16) /* German */
ASSIGN("dz", 0x17) /* Bhutani */
ASSIGN("el", 0x18) /* Greek */
ASSIGN("en", 0x19) /* English */
ASSIGN("eo", 0x1a) /* Esperanto */
ASSIGN("es", 0x1b) /* Spanish */
ASSIGN("et", 0x1c) /* Estonian */
ASSIGN("eu", 0x1d) /* Basque */
ASSIGN("fa", 0x1e) /* Persian */
ASSIGN("fi", 0x1f) /* Finnish */
ASSIGN("fj", 0x20) /* Fiji */
ASSIGN("fo", 0x82) /* Faroese */
ASSIGN("fr", 0x22) /* French */
ASSIGN("fy", 0x83) /* Frisian */
ASSIGN("ga", 0x24) /* Irish */
ASSIGN("gd", 0x25) /* Scots Gaelic */
ASSIGN("gl", 0x26) /* Galician */
ASSIGN("gn", 0x27) /* Guarani */
ASSIGN("gu", 0x28) /* Gujarati */
ASSIGN("ha", 0x29) /* Hausa */
ASSIGN("he", 0x2a) /* Hebrew (formerly iw) */
ASSIGN("hi", 0x2b) /* Hindi */
ASSIGN("hr", 0x2c) /* Croatian */
ASSIGN("hu", 0x2d) /* Hungarian */
ASSIGN("hy", 0x2e) /* Armenian */
ASSIGN("ia", 0x84) /* Interlingua */
ASSIGN("id", 0x30) /* Indonesian (formerly in) */
ASSIGN("ie", 0x86) /* Interlingue */
ASSIGN("ik", 0x87) /* Inupiak */
ASSIGN("is", 0x33) /* Icelandic */
ASSIGN("it", 0x34) /* Italian */
ASSIGN("iu", 0x89) /* Inuktitut */
ASSIGN("ja", 0x36) /* Japanese */
ASSIGN("jw", 0x37) /* Javanese */
ASSIGN("ka", 0x38) /* Georgian */
ASSIGN("kk", 0x39) /* Kazakh */
ASSIGN("kl", 0x8a) /* Greenlandic */
ASSIGN("km", 0x3b) /* Cambodian */
ASSIGN("kn", 0x3c) /* Kannada */
ASSIGN("ko", 0x3d) /* Korean */
ASSIGN("ks", 0x3e) /* Kashmiri */
ASSIGN("ku", 0x3f) /* Kurdish */
ASSIGN("ky", 0x40) /* Kirghiz */
ASSIGN("la", 0x8b) /* Latin */
ASSIGN("ln", 0x42) /* Lingala */
ASSIGN("lo", 0x43) /* Laothian */
ASSIGN("lt", 0x44) /* Lithuanian */
ASSIGN("lv", 0x45) /* Latvian, Lettish */
ASSIGN("mg", 0x46) /* Malagasy */
ASSIGN("mi", 0x47) /* Maori */
ASSIGN("mk", 0x48) /* Macedonian */
ASSIGN("ml", 0x49) /* Malayalam */
ASSIGN("mn", 0x4a) /* Mongolian */
ASSIGN("mo", 0x4b) /* Moldavian */
ASSIGN("mr", 0x4c) /* Marathi */
ASSIGN("ms", 0x4d) /* Malay */
ASSIGN("mt", 0x4e) /* Maltese */
ASSIGN("my", 0x4f) /* Burmese */
ASSIGN("na", 0x81) /* Nauru */
ASSIGN("ne", 0x51) /* Nepali */
ASSIGN("nl", 0x52) /* Dutch */
ASSIGN("no", 0x53) /* Norwegian */
ASSIGN("oc", 0x54) /* Occitan */
ASSIGN("om", 0x55) /* (Afan) Oromo */
ASSIGN("or", 0x56) /* Oriya */
ASSIGN("pa", 0x57) /* Punjabi */
ASSIGN("pl", 0x58) /* Polish */
ASSIGN("ps", 0x59) /* Pashto, Pushto */
ASSIGN("pt", 0x5a) /* Portuguese */
ASSIGN("qu", 0x5b) /* Quechua */
ASSIGN("rm", 0x8c) /* Rhaeto-Romance */
ASSIGN("rn", 0x5d) /* Kirundi */
ASSIGN("ro", 0x5e) /* Romanian */
ASSIGN("ru", 0x5f) /* Russian */
ASSIGN("rw", 0x60) /* Kinyarwanda */
ASSIGN("sa", 0x61) /* Sanskrit */
ASSIGN("sd", 0x62) /* Sindhi */
ASSIGN("sg", 0x63) /* Sangro (Sangho) */
ASSIGN("sh", 0x64) /* Serbo-Croatian */
ASSIGN("si", 0x65) /* Sinhalese */
ASSIGN("sk", 0x66) /* Slovak */
ASSIGN("sl", 0x67) /* Slovenian */
ASSIGN("sm", 0x68) /* Samoan */
ASSIGN("sn", 0x69) /* Shona */
ASSIGN("so", 0x6a) /* Somali */
ASSIGN("sq", 0x6b) /* Albanian */
ASSIGN("sr", 0x6c) /* Serbian */
ASSIGN("ss", 0x6d) /* Siswati */
ASSIGN("st", 0x6e) /* Sesotho */
ASSIGN("su", 0x6f) /* Sundanese */
ASSIGN("sv", 0x70) /* Swedish */
ASSIGN("sw", 0x71) /* Swahili */
ASSIGN("ta", 0x72) /* Tamil */
ASSIGN("te", 0x73) /* Telugu */
ASSIGN("tg", 0x74) /* Tajik */
ASSIGN("th", 0x75) /* Thai */
ASSIGN("ti", 0x76) /* Tigrinya */
ASSIGN("tk", 0x77) /* Turkmen */
ASSIGN("tl", 0x78) /* Tagalog */
ASSIGN("tn", 0x79) /* Setswana */
ASSIGN("to", 0x7a) /* Tonga */
ASSIGN("tr", 0x7b) /* Turkish */
ASSIGN("ts", 0x7c) /* Tsonga */
ASSIGN("tt", 0x7d) /* Tatar */
ASSIGN("tw", 0x7e) /* Twi */
ASSIGN("ug", 0x7f) /* Uighur */
ASSIGN("uk", 0x50) /* Ukrainian */
ASSIGN("ur", 0x21) /* Urdu */
ASSIGN("uz", 0x23) /* Uzbek */
ASSIGN("vi", 0x2f) /* Vietnamese */
ASSIGN("vo", 0x85) /* Volapuk */
ASSIGN("wo", 0x31) /* Wolof */
ASSIGN("xh", 0x32) /* Xhosa */
ASSIGN("yi", 0x88) /* Yiddish (formerly ji) */
ASSIGN("yo", 0x35) /* Yoruba */
ASSIGN("za", 0x3a) /* Zhuang */
ASSIGN("zh", 0x41) /* Chinese */
ASSIGN("zu", 0x5c) /* Zulu */
)
/* Well known methods, from table 34. */
NUMBERED(method,
ASSIGN("GET", 0x40)
ASSIGN("OPTIONS", 0x41)
ASSIGN("HEAD", 0x42)
ASSIGN("DELETE", 0x43)
ASSIGN("TRACE", 0x44)
ASSIGN("POST", 0x60)
ASSIGN("PUT", 0x61)
ASSIGN("DATA", 0x80)
)
/* Connection-value tokens, from section 8.4.2.16 */
LINEAR(connection,
STRING("close")
)
/* Transfer-encoding values, from section 8.4.2.46 */
LINEAR(transfer_encoding,
STRING("chunked")
)
/* Well-known bearer type codes, from WDP Appendix C */
LINEAR(bearer_indication,
STRING("any_ipv4")
STRING("any_ipv6")
STRING("gsm_usd_any")
STRING("gsm_sms_gsmmsisdn")
STRING("ansi-136_guts/r-data_ansi_136_msisdn")
STRING("is-95_cdma_sms_is_637_msisdn")
STRING("is-95_cdma_csd_ipv4")
STRING("is-95_packet_data_ipv4")
STRING("ansi-136_csd_ipv4")
STRING("ansi-136_packet_data_ipv4")
STRING("gsm_csd_ipv4")
STRING("gsm_gprs_ipv4")
STRING("gsm_ussd_ipv4")
STRING("amps_cdpd_ipv4")
STRING("pdc_csd_ipv4")
STRING("pdc_packet_data_ipv4")
STRING("iden_sms_iden_msisdn")
STRING("iden_csd_ipv4")
STRING("iden_packet_data_ipv4")
STRING("paging_network_flex_flex_msisdn")
STRING("phs_sms_phs_msisdn")
STRING("phs_csd_ipv4")
STRING("gsm_ussd_gsm_service_code")
STRING("tetra_sds_tetra_itsi")
STRING("tetra_sds_tetra_msisdn")
STRING("tetra_packet_data_ipv4")
STRING("paging_network_reflex_reflex_isdn")
STRING("gsm_ussd_gsm_msisdn")
STRING("mobitex_mpak_man")
STRING("ansi-136_ghost/r_data_gsm_isdn")
)
/*
* Well known and registered push application ids, see URL
*
* http://www.openmobilealliance.org/tech/omna/omna-push-app-id.htm (depricated)
* http://www.openmobilealliance.org/Technical/omna/omna-push-app-id.aspx
*
* Note that generic id strings do not contain the "x-wap-application" prefix,
* it's the default, otherwise an alternate is given.
*/
NUMBERED(application_id,
ASSIGN("*", 0x00)
ASSIGN("push.sia", 0x01)
ASSIGN("wml.ua", 0x02)
ASSIGN("wta.ua", 0x03)
ASSIGN("mms.ua", 0x04)
ASSIGN("push.syncml", 0x05)
ASSIGN("loc.ua", 0x06)
ASSIGN("syncml.dm", 0x07)
ASSIGN("drm.ua", 0x08)
ASSIGN("emn.ua", 0x09)
ASSIGN("wv.ua", 0x0A)
ASSIGN("x-oma-application:ulp.ua", 0x10)
ASSIGN("x-oma-application:dlota.ua", 0x11)
ASSIGN("x-oma-application:java-ams", 0x12)
ASSIGN("x-oma-application:bcast.ua", 0x13)
ASSIGN("x-wap-microsoft:localcontent.ua", 0x8000)
ASSIGN("x-wap-microsoft:IMclient.ua", 0x8001)
ASSIGN("x-wap-docomo:imode.mail.ua", 0x8002)
ASSIGN("x-wap-docomo:imode.mr.ua", 0x8003)
ASSIGN("x-wap-docomo:imode.mf.ua", 0x8004)
ASSIGN("x-motorola:location.ua", 0x8005)
ASSIGN("x-motorola:now.ua", 0x8006)
ASSIGN("x-motorola:otaprov.ua", 0x8007)
ASSIGN("x-motorola:browser.ua", 0x8008)
ASSIGN("x-motorola:splash.ua", 0x8009)
ASSIGN("x-wap-nai:mvsw.command", 0x800B)
ASSIGN("x-wap-openvawe:iota.ua", 0x8010)
ASSIGN("x-wap-docomo:imode.mail2.ua", 0x9000)
ASSIGN("x-oma-nec:otaprov.ua", 0x9001)
ASSIGN("x-oma-nokia:call.ua", 0x9002)
ASSIGN("x-oma-coremobility:sqa.ua", 0x9003)
ASSIGN("x-oma-docomo:doja.jam.ua", 0x9004)
ASSIGN("x-oma-nokia:sip.ua", 0x9010)
ASSIGN("x-oma-vodafone:otaprov.ua", 0x9011)
ASSIGN("x-hutchison:ad.ua", 0x9012)
ASSIGN("x-oma-nokia:voip.ua", 0x9013)
ASSIGN("x-oma-docomo:voice.ua", 0x9014)
ASSIGN("x-oma-docomo:browser.ctl", 0x9015)
ASSIGN("x-oma-docomo:dan.ua", 0x9016)
ASSIGN("x-oma-nokia:vs.ua", 0x9017)
ASSIGN("x-oma-nokia:voip.ext1.ua", 0x9018)
ASSIGN("x-wap-vodafone:casting.ua", 0x9019)
ASSIGN("x-oma-docomo:imode.data.ua", 0x901A)
ASSIGN("x-oma-snapin:otaprov.ctl", 0x901B)
ASSIGN("x-oma-nokia:vrs.ua", 0x901C)
ASSIGN("x-oma-nokia:vrpg.ua", 0x901D)
ASSIGN("x-oma-motorola:screen3.ua", 0x901E)
ASSIGN("x-oma-docomo:device.ctl", 0x901F)
ASSIGN("x-oma-nokia:msc.ua", 0x9020)
ASSIGN("x-3gpp2:lcs.ua", 0x9021)
ASSIGN("x-wap-vodafone:dcd.ua", 0x9022)
ASSIGN("x-3gpp:mbms.service.announcement.ua", 0x9023)
ASSIGN("x-oma-vodafone:dltmtbl.ua", 0x9024)
ASSIGN("x-oma-vodafone:dvcctl.ua", 0x9025)
ASSIGN("x-oma-cmcc:mail.ua", 0x9026)
ASSIGN("x-oma-nokia:vmb.ua", 0x9027)
ASSIGN("x-oma-nokia:ldapss.ua", 0x9028)
ASSIGN("x-hutchison:al.ua", 0x9029)
ASSIGN("x-oma-nokia:uma.ua", 0x902A)
ASSIGN("x-oma-nokia:news.ua", 0x902B)
ASSIGN("x-oma-docomo:pf", 0x902C)
ASSIGN("x-oma-docomo:ub", 0x902D)
ASSIGN("x-oma-nokia:nat.traversal.ua", 0x902E)
ASSIGN("x-oma-intromobile:intropad.ua", 0x902F)
ASSIGN("x-oma-docomo:uin.ua", 0x9030)
ASSIGN("x-oma-nokia:iptv.ua", 0x9031)
ASSIGN("x-hutchison:il.ua", 0x9032)
ASSIGN("x-oma-nokia:voip.general.ua", 0x9033)
ASSIGN("x-microsoft:drm.meter", 0x9034)
ASSIGN("x-microsoft:drm.license", 0x9035)
ASSIGN("x-oma-docomo:ic.ctl", 0x9036)
ASSIGN("x-oma-slingmedia:SPM.ua", 0x9037)
ASSIGN("x-cibenix:odp.ua", 0x9038)
ASSIGN("x-oma-motorola:voip.ua", 0x9039)
ASSIGN("x-oma-motorola:ims", 0x903A)
ASSIGN("x-oma-docomo:imode.remote.ctl", 0x903B)
ASSIGN("x-oma-docomo:device.ctl.um", 0x903C)
ASSIGN("x-microsoft:playready.drm.initiator", 0x903D)
ASSIGN("x-microsoft:playready.drm", 0x903E)
ASSIGN("x-oma-sbm:ms.mexa.ua", 0x903F)
ASSIGN("urn:oma:drms:org-LGE:L650V", 0x9040)
ASSIGN("x-oma-docomo:um", 0x9041)
ASSIGN("x-oma-docomo:uin.um", 0x9042)
ASSIGN("urn:oma:drms:org-LGE:KU450", 0x9043)
ASSIGN("x-wap-microsoft:cfgmgr.ua", 0x9044)
ASSIGN("x-3gpp:mbms.download.delivery.ua", 0x9045)
ASSIGN("x-oma-docomo:star.ctl", 0x9046)
ASSIGN("urn:oma:drms:org-LGE:KU380", 0x9047)
ASSIGN("x-oma-docomo:pf2", 0x9048)
ASSIGN("x-oma-motorola:blogcentral.ua", 0x9049)
ASSIGN("x-oma-docomo:imode.agent.ua", 0x904A)
ASSIGN("x-wap-application:push.sia", 0x904B)
ASSIGN("x-oma-nokia:destination.network.ua", 0x904C)
ASSIGN("x-oma-sbm:mid2.ua", 0x904D)
)
/**** More preprocessor magic ****/
#undef LINEAR
#undef STRING
#undef VSTRING
#undef NUMBERED
#undef ASSIGN
#undef VASSIGN
#undef NAMED
#undef NSTRING
#undef VNSTRING
gateway-1.4.3/wap/wtp_resp.h 0000644 0001750 0001750 00000010646 11132672002 015022 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* WTP responder header
*
* Aarno Syvnen for Wapit Ltd
*/
#ifndef WTP_RESPONDER_H
#define WTP_RESPONDER_H
typedef struct WTPRespMachine WTPRespMachine;
#include "gwlib/gwlib.h"
#include "wap_events.h"
#include "timers.h"
typedef struct sar_info_t {
int sar_psn;
Octstr *sar_data;
} sar_info_t;
/*
* Structure to keep SAR data during transmission
*/
typedef struct WTPSARData {
int nsegm; /* number of the last segment, i.e. total number - 1 */
int csegm; /* last segment confirmed by recipient */
int lsegm; /* last sent segment */
int tr; /* if current psn is gtr or ttr */
Octstr *data;
} WTPSARData;
/*
* Maximum segment size. (Nokia WAP GW uses the size of 576,
* but mobiles use 1,5K size).
*/
#define SAR_SEGM_SIZE 1400
#define SAR_GROUP_LEN 3
/*
* Responder machine states and responder WTP machine.
* See file wtp_resp_state-decl.h for comments. Note that we must define macro
* ROW to produce an empty string.
*/
enum resp_states {
#define STATE_NAME(state) state,
#define ROW(state, event, condition, action, next_state)
#include "wtp_resp_states.def"
resp_states_count
};
typedef enum resp_states resp_states;
/*
* See files wtp_resp_machine-decl.h and for comments. We define one macro for
* every separate type.
*/
struct WTPRespMachine {
unsigned long mid;
#define INTEGER(name) int name;
#define TIMER(name) Timer *name;
#define ADDRTUPLE(name) WAPAddrTuple *name;
#define ENUM(name) resp_states name;
#define EVENT(name) WAPEvent *name;
#define LIST(name) List *name;
#define SARDATA(name) WTPSARData *name;
#define MACHINE(field) field
#include "wtp_resp_machine.def"
};
#endif
gateway-1.4.3/wap/wtp_pack.c 0000644 0001750 0001750 00000022215 11132672002 014755 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation includPd with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software eveloped by the
* Kannl Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_pack.c - WTP message packing module implementation
*
* By Aarno Syvnen for WapIT Ltd.
*/
#include "gwlib/gwlib.h"
#include "wtp_pack.h"
#include "wtp_pdu.h"
/*
* Readable names for octets
*/
enum {
first_byte,
second_byte,
third_byte,
fourth_byte
};
/*
* Types of header information added by the user (TPIs, or transportation
* information items).
*/
enum {
ERROR_DATA = 0x00,
INFO_DATA = 0x01,
OPTION = 0x02,
PACKET_SEQUENCE_NUMBER = 0x03,
SDU_BOUNDARY = 0x04,
FRAME_BOUNDARY = 0x05
};
/*****************************************************************************
*
* Prototypes of internal functions
*/
/*
* WTP defines SendTID and RcvTID. We should use SendTID in all PDUs
* we send. The RcvTID is the one we got from the initial Invoke and
* is the one we expect on all future PDUs for this machine.
* SendTID is always RcvTID xor 0x8000.
*
* Note that when we are the Initiator, for example with WSP PUSH,
* we must still store the RcvTID in machine->tid, to be consistent
* with the current code. So we'll choose the SendTID and then calculate
* the RcvTID.
*/
static unsigned short send_tid(unsigned short tid);
/*****************************************************************************
*
* EXTERNAL FUNCTIONS:
*
*/
WAPEvent *wtp_pack_invoke(WTPInitMachine *machine, WAPEvent *event)
{
WAPEvent *dgram = NULL;
WTP_PDU *pdu = NULL;
gw_assert(event->type == TR_Invoke_Req);
pdu = wtp_pdu_create(Invoke);
pdu->u.Invoke.con = 0;
pdu->u.Invoke.gtr = 1;
pdu->u.Invoke.ttr = 1;
pdu->u.Invoke.rid = 0;
pdu->u.Invoke.version = 0;
pdu->u.Invoke.tid = send_tid(machine->tid);
pdu->u.Invoke.tidnew = machine->tidnew;
pdu->u.Invoke.user_data =
octstr_duplicate(event->u.TR_Invoke_Req.user_data);
pdu->u.Invoke.class = event->u.TR_Invoke_Req.tcl;
pdu->u.Invoke.uack = event->u.TR_Invoke_Req.up_flag;
dgram = wap_event_create(T_DUnitdata_Req);
dgram->u.T_DUnitdata_Req.addr_tuple =
wap_addr_tuple_duplicate(machine->addr_tuple);
dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
wtp_pdu_destroy(pdu);
return dgram;
}
WAPEvent *wtp_pack_result(WTPRespMachine *machine, WAPEvent *event)
{
WAPEvent *dgram = NULL;
WTP_PDU *pdu = NULL;
gw_assert(event->type == TR_Result_Req);
pdu = wtp_pdu_create(Result);
pdu->u.Result.con = 0;
pdu->u.Result.gtr = 1;
pdu->u.Result.ttr = 1;
pdu->u.Result.rid = 0;
pdu->u.Result.tid = send_tid(machine->tid);
pdu->u.Result.user_data =
octstr_duplicate(event->u.TR_Result_Req.user_data);
dgram = wap_event_create(T_DUnitdata_Req);
dgram->u.T_DUnitdata_Req.addr_tuple =
wap_addr_tuple_duplicate(machine->addr_tuple);
dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
wtp_pdu_destroy(pdu);
return dgram;
}
WAPEvent *wtp_pack_sar_result(WTPRespMachine *machine, int psn)
{
WAPEvent *dgram = NULL;
WTP_PDU *pdu = NULL;
Octstr *data = NULL;
int gtr, ttr;
gw_assert(machine->sar && machine->sar->data);
if (psn > machine->sar->nsegm)
return dgram;
ttr = psn == machine->sar->nsegm ? 1 : 0;
gtr = ttr ? 0 : (psn+1)%SAR_GROUP_LEN ? 0 : 1;
if (gtr || ttr)
machine->sar->tr = 1;
data = octstr_copy(machine->sar->data,psn*SAR_SEGM_SIZE,SAR_SEGM_SIZE);
if (!psn) {
pdu = wtp_pdu_create(Result);
pdu->u.Result.con = 0;
pdu->u.Result.gtr = gtr;
pdu->u.Result.ttr = ttr;
pdu->u.Result.rid = 0;
pdu->u.Result.tid = send_tid(machine->tid);
pdu->u.Result.user_data = data;
} else {
pdu = wtp_pdu_create(Segmented_result);
pdu->u.Segmented_result.con = 0;
pdu->u.Segmented_result.gtr = gtr;
pdu->u.Segmented_result.ttr = ttr;
pdu->u.Segmented_result.rid = 0;
pdu->u.Segmented_result.tid = send_tid(machine->tid);
pdu->u.Segmented_result.psn = psn;
pdu->u.Segmented_result.user_data = data;
}
dgram = wap_event_create(T_DUnitdata_Req);
dgram->u.T_DUnitdata_Req.addr_tuple =
wap_addr_tuple_duplicate(machine->addr_tuple);
dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
wtp_pdu_destroy(pdu);
return dgram;
}
void wtp_pack_set_rid(WAPEvent *dgram, long rid)
{
gw_assert(dgram != NULL);
gw_assert(dgram->type == T_DUnitdata_Req);
octstr_set_bits(dgram->u.T_DUnitdata_Req.user_data, 7, 1, rid);
}
WAPEvent *wtp_pack_abort(long abort_type, long abort_reason, long tid,
WAPAddrTuple *address)
{
WAPEvent *dgram;
WTP_PDU *pdu;
pdu = wtp_pdu_create(Abort);
pdu->u.Abort.con = 0;
pdu->u.Abort.abort_type = abort_type;
pdu->u.Abort.tid = send_tid(tid);
pdu->u.Abort.abort_reason = abort_reason;
dgram = wap_event_create(T_DUnitdata_Req);
dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address);
dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
wtp_pdu_destroy(pdu);
return dgram;
}
WAPEvent *wtp_pack_ack(long ack_type, int rid_flag, long tid,
WAPAddrTuple *address)
{
WAPEvent *dgram = NULL;
WTP_PDU *pdu;
pdu = wtp_pdu_create(Ack);
pdu->u.Ack.con = 0;
pdu->u.Ack.tidverify = ack_type;
pdu->u.Ack.rid = rid_flag;
pdu->u.Ack.tid = send_tid(tid);
dgram = wap_event_create(T_DUnitdata_Req);
dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address);
dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
wtp_pdu_destroy(pdu);
return dgram;
}
WAPEvent *wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn)
{
WAPEvent *dgram = NULL;
WTP_PDU *pdu;
unsigned char cpsn = psn;
pdu = wtp_pdu_create(Ack);
pdu->u.Ack.con = 1;
pdu->u.Ack.tidverify = ack_type;
pdu->u.Ack.rid = 0;
pdu->u.Ack.tid = send_tid(tid);
wtp_pdu_append_tpi(pdu, 3, octstr_create_from_data((char*) &cpsn, 1));
dgram = wap_event_create(T_DUnitdata_Req);
dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address);
dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
wtp_pdu_destroy(pdu);
return dgram;
}
/****************************************************************************
*
* INTERNAL FUNCTIONS:
*
*/
static unsigned short send_tid(unsigned short tid)
{
return tid ^ 0x8000;
}
/****************************************************************************/
gateway-1.4.3/wap/wsp_push_client.c 0000644 0001750 0001750 00000033577 11132672004 016372 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_push_client.c: Client WSP Push implementation, for testing purposes
*
* Aarno Syvnen for Wapit Ltd
*/
#include "wsp_push_client.h"
#include "wsp.h"
#include "wtp.h"
#include "wsp_pdu.h"
#include "wsp_headers.h"
#include "wap.h"
/**************************************************************************
*
* Internal data structures:
*
* List of client WSP push machines.
*/
static List *push_client_machines = NULL;
/*
* Counter for client push machine id numbers, to make sure that they are
* unique.
*/
static Counter *push_client_machine_id_counter = NULL;
/*
* Give the status of push client:
*
* limbo
* not running at all
* running
* operating normally
* terminating
* waiting for operations to terminate, returning to limbo
*/
static enum {limbo, running, terminating } push_client_run_status = limbo;
/*
* Queue of events to be handled by the push client.
*/
static List *push_client_queue = NULL;
wap_dispatch_func_t *dispatch_to_self;
wap_dispatch_func_t *dispatch_to_wtp_resp;
/*****************************************************************************
*
* Prototypes of internal functions:
*
* Create and destroy an uniniatilised push client state machine.
*/
static WSPPushClientMachine *push_client_machine_create(long cpid);
static void push_client_machine_destroy(void *a);
/*
* Checks whether the client push machines list includes a specific machine.
* Creates it, if the event is TR-Invoke.ind
*/
static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e);
/*
* Feed an event to the client push state machine. Do not report errors to
* caller.
*/
static void push_client_event_handle(WSPPushClientMachine *cpm, WAPEvent *e);
/*
* Print WSP client push machine state as a string.
*/
static unsigned char *name_push_client_state(int name);
static void main_thread(void *);
static WAPEvent *indicate_confirmedpush(WSPPushClientMachine *cpm,
Octstr *push_body);
static WAPEvent *indicate_pushabort(WSPPushClientMachine *cpm,
long abort_reason);
static WAPEvent *response_confirmedpush(WSPPushClientMachine *cpm);
static WAPEvent *send_abort_to_responder(WSPPushClientMachine *cpm, long reason);
static WAPEvent *response_responder_invoke(WSPPushClientMachine *cpm);
/**************************************************************************
*
* EXTERNAL FUNCTIONS:
*
*/
void wsp_push_client_init(wap_dispatch_func_t *dispatch_self,
wap_dispatch_func_t *dispatch_wtp_resp)
{
push_client_machines = gwlist_create();
push_client_machine_id_counter = counter_create();
push_client_queue = gwlist_create();
gwlist_add_producer(push_client_queue);
dispatch_to_self = dispatch_self;
dispatch_to_wtp_resp = dispatch_wtp_resp;
gw_assert(push_client_run_status == limbo);
push_client_run_status = running;
gwthread_create(main_thread, NULL);
}
void wsp_push_client_shutdown(void)
{
gw_assert(push_client_run_status == running);
push_client_run_status = terminating;
gwlist_remove_producer(push_client_queue);
gwthread_join_every(main_thread);
debug("wap.wsp", 0, "wsp_push_client_shutdown: %ld push client machines"
"left", gwlist_len(push_client_machines));
gwlist_destroy(push_client_machines, push_client_machine_destroy);
gwlist_destroy(push_client_queue, wap_event_destroy_item);
counter_destroy(push_client_machine_id_counter);
}
void wsp_push_client_dispatch_event(WAPEvent *e)
{
gwlist_produce(push_client_queue, e);
}
/***************************************************************************
*
* INTERNAL FUNCTIONS:
*
*/
static void main_thread(void *arg)
{
WSPPushClientMachine *cpm;
WAPEvent *e;
while (push_client_run_status == running &&
(e = gwlist_consume(push_client_queue)) != NULL) {
cpm = push_client_machine_find_or_create(e);
if (cpm == NULL)
wap_event_destroy(e);
else
push_client_event_handle(cpm, e);
}
}
/*
* Give the name of a push client machine state in a readable form
*/
static unsigned char *name_push_client_state(int n) {
switch (n) {
#define PUSH_CLIENT_STATE_NAME(state) case state : return (unsigned char *)#state;
#define ROW(state, event, condition, action, new_state)
#include "wsp_push_client_states.def"
default:
return (unsigned char *)"unknown state";
}
}
/*
* Feed an event to a WSP push client state machine. Do not report errors to
* the caller.
*/
static void push_client_event_handle(WSPPushClientMachine *cpm,
WAPEvent *e)
{
WAPEvent *wtp_event;
WSP_PDU *pdu = NULL;
wap_event_assert(e);
gw_assert(cpm);
if (e->type == TR_Invoke_Ind) {
pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data);
/*
* Class 1 tests here
* Case 4, no session matching address quadruplet, handled by the session mach-
* ine.
* Tests from table WSP, page 45. Case 5, a PDU state tables cannot handle.
*/
if (pdu == NULL || pdu->type != ConfirmedPush) {
wap_event_destroy(e);
wtp_event = send_abort_to_responder(cpm, PROTOERR);
wtp_resp_dispatch_event(wtp_event);
return;
}
}
debug("wap.wsp", 0, "WSP_PUSH: WSPPushClientMachine %ld, state %s,"
" event %s",
cpm->client_push_id,
name_push_client_state(cpm->state),
wap_event_name(e->type));
#define PUSH_CLIENT_STATE_NAME(state)
#define ROW(push_state, event_type, condition, action, next_state) \
if (cpm->state == push_state && \
e->type == event_type && \
(condition)) { \
action \
cpm->state = next_state; \
debug("wap.wsp", 0, "WSP_PUSH %ld: new state %s", \
cpm->client_push_id, #next_state); \
} else
#include "wsp_push_client_states.def"
{
error(0, "WSP_PUSH: handle_event: unhandled event!");
debug("wap.wsp", 0, "Unhandled event was:");
wap_event_dump(e);
wap_event_destroy(e);
return;
}
wsp_pdu_destroy(pdu);
wap_event_destroy(e);
if (cpm->state == PUSH_CLIENT_NULL_STATE)
push_client_machine_destroy(cpm);
}
static int push_client_machine_has_transid(void *a, void *b)
{
long transid;
WSPPushClientMachine *m;
m = a;
transid = *(long *)b;
return m->transaction_id == transid;
}
static WSPPushClientMachine *push_client_machine_find_using_transid(
long transid)
{
WSPPushClientMachine *m;
m = gwlist_search(push_client_machines, &transid,
push_client_machine_has_transid);
return m;
}
/*
* Checks client push machines list for a specific machine. Creates it, if the
* event is TR-Invoke.ind.
* Client push machine is identified (when searching) by transcation identifi-
* er.
* Note that only WTP responder send its class 1 messages to client push state
* machine. So, it is no need to specify WTP machine type.
*/
static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e)
{
WSPPushClientMachine *cpm;
long transid;
cpm = NULL;
transid = -1;
switch (e->type) {
case TR_Invoke_Ind:
transid = e->u.TR_Invoke_Ind.handle;
break;
case S_ConfirmedPush_Res:
transid = e->u.S_ConfirmedPush_Res.client_push_id;
break;
case S_PushAbort_Req:
transid = e->u.S_PushAbort_Req.push_id;
break;
case Abort_Event:
break;
case TR_Abort_Ind:
transid = e->u.TR_Abort_Ind.handle;
break;
default:
debug("wap.wsp", 0, "WSP PUSH: push_client_find_or_create: unhandled"
" event");
wap_event_dump(e);
wap_event_destroy(e);
return NULL;
}
gw_assert(transid != -1);
cpm = push_client_machine_find_using_transid(transid);
if (cpm == NULL) {
switch (e->type) {
case TR_Invoke_Ind:
cpm = push_client_machine_create(transid);
break;
case S_ConfirmedPush_Res:
case S_PushAbort_Req:
error(0, "WSP_PUSH_CLIENT: POT primitive to a nonexisting"
" push client machine");
break;
case Abort_Event:
error(0, "WSP_PUSH_CLIENT: internal abort to a nonexisting"
" push client machine");
break;
case TR_Abort_Ind:
error(0, "WSP_PUSH_CLIENT: WTP abort to a nonexisting push client"
" machine");
break;
default:
error(0, "WSP_PUSH_CLIENT: Cannot handle event type %s",
wap_event_name(e->type));
break;
}
}
return cpm;
}
static WSPPushClientMachine *push_client_machine_create(long transid)
{
WSPPushClientMachine *m;
m = gw_malloc(sizeof(WSPPushClientMachine));
debug("wap.wsp", 0, "WSP_PUSH_CLIENT: Created WSPPushClientMachine %p",
(void *) m);
#define INTEGER(name) m->name = 0;
#define HTTPHEADERS(name) m->name = NULL;
#define MACHINE(fields) fields
#include "wsp_push_client_machine.def"
m->state = PUSH_CLIENT_NULL_STATE;
m->transaction_id = transid;
m->client_push_id = counter_increase(push_client_machine_id_counter);
gwlist_append(push_client_machines, m);
return m;
}
static void push_client_machine_destroy(void *a)
{
WSPPushClientMachine *m;
m = a;
debug("wap.wsp", 0, "Destroying WSPPushClientMachine %p", (void *) m);
gwlist_delete_equal(push_client_machines, m);
#define INTEGER(name) m->name = 0;
#define HTTPHEADERS(name) http_destroy_headers(m->name);
#define MACHINE(fields) fields;
#include "wsp_push_client_machine.def"
gw_free(m);
}
static WAPEvent *indicate_confirmedpush(WSPPushClientMachine *cpm,
Octstr *push_body)
{
WAPEvent *e;
e = wap_event_create(S_ConfirmedPush_Ind);
e->u.S_ConfirmedPush_Ind.client_push_id = cpm->client_push_id;
e->u.S_ConfirmedPush_Ind.push_headers =
http_header_duplicate(cpm->push_headers);
e->u.S_ConfirmedPush_Ind.push_body = octstr_duplicate(push_body);
return e;
}
static WAPEvent *indicate_pushabort(WSPPushClientMachine *cpm,
long abort_reason)
{
WAPEvent *e;
e = wap_event_create(S_PushAbort_Ind);
e->u.S_PushAbort_Ind.push_id = cpm->client_push_id;
e->u.S_PushAbort_Ind.reason = abort_reason;
return e;
}
/*
* For debugging: create S-ConfirmedPush.res by ourselves.
*/
static WAPEvent *response_confirmedpush(WSPPushClientMachine *cpm)
{
WAPEvent *e;
e = wap_event_create(S_ConfirmedPush_Res);
e->u.S_ConfirmedPush_Res.client_push_id = cpm->client_push_id;
return e;
}
static WAPEvent *send_abort_to_responder(WSPPushClientMachine *cpm,
long reason)
{
WAPEvent *e;
e = wap_event_create(TR_Abort_Req);
e->u.TR_Abort_Req.abort_type = USER;
e->u.TR_Abort_Req.abort_reason = reason;
e->u.TR_Abort_Req.handle = cpm->client_push_id;
return e;
}
static WAPEvent *response_responder_invoke(WSPPushClientMachine *cpm)
{
WAPEvent *e;
e = wap_event_create(TR_Invoke_Res);
e->u.TR_Invoke_Res.handle = cpm->transaction_id;
return e;
}
gateway-1.4.3/wap/wtls_pdu.c 0000644 0001750 0001750 00000125524 11132672003 015016 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtls_pdu.c: pack and unpack WTLS packets
*
* Generates packing and unpacking code from wtls_pdu.def.
*
*/
#include "gwlib/gwlib.h"
#if (HAVE_WTLS_OPENSSL)
#include "gwlib/octstr.h"
#include "wtls_pdu.h"
#include "wtls_pdusupport.h"
#include "wtls_statesupport.h"
KeyExchangeSuite client_key_exchange_algo = rsa_anon;
PublicKeyAlgorithm public_key_algo;
SignatureAlgorithm signature_algo;
int seqnum;
wtls_Payload* wtls_payload_unpack_from_offset (Octstr *data, int *offset);
wtls_PDU *wtls_pdu_create(int type) {
wtls_PDU *pdu;
pdu = gw_malloc(sizeof(*pdu));
pdu->type = type;
pdu->reserved = 0;
pdu->cipher = 0;
pdu->seqnum = 0;
pdu->rlen = 0;
switch (pdu->type) {
case ChangeCipher_PDU:
pdu->u.cc.change = 1;
break;
case Alert_PDU:
pdu->u.alert.level = 0;
pdu->u.alert.desc = 0;
pdu->u.alert.chksum = 0;
break;
case Handshake_PDU:
pdu->u.handshake.msg_type = 0;
pdu->u.handshake.length = 0;
break;
case Application_PDU:
pdu->u.application.data = NULL;
break;
default:
warning(0, "Cannot create unknown WTLS PDU type %d", pdu->type);
break;
}
return pdu;
}
void wtls_payload_destroy(wtls_Payload *payload) {
octstr_destroy(payload->data);
gw_free(payload);
}
void wtls_pdu_destroy(wtls_PDU *pdu) {
if (pdu == NULL)
return;
switch (pdu->type) {
case ChangeCipher_PDU:
/* no memory was allocated for ChangeCipher_PDU */
break;
case Alert_PDU:
octstr_destroy(pdu->u.alert.chksum );
break;
case Handshake_PDU:
switch (pdu->u.handshake.msg_type) {
case hello_request:
break;
case client_hello:
destroy_random(pdu->u.handshake.client_hello->random);
octstr_destroy(pdu->u.handshake.client_hello->session_id);
destroy_key_list(pdu->u.handshake.client_hello->client_key_ids);
destroy_key_list(pdu->u.handshake.client_hello->trusted_key_ids);
destroy_ciphersuite_list(pdu->u.handshake.client_hello->ciphersuites);
destroy_compression_method_list(pdu->u.handshake.client_hello->comp_methods);
/* destroy the client_hello struct */
gw_free(pdu->u.handshake.client_hello);
break;
case server_hello:
destroy_random(pdu->u.handshake.server_hello->random);
octstr_destroy(pdu->u.handshake.server_hello->session_id);
/* destroy the server_hello struct */
gw_free(pdu->u.handshake.server_hello);
break;
case certificate:
switch (pdu->u.handshake.certificate->certificateformat) {
case WTLSCert:
destroy_wtls_certificate(pdu->u.handshake.certificate->wtls_certificate);
break;
case X509Cert:
octstr_destroy(pdu->u.handshake.certificate->x509_certificate);
break;
case X968Cert:
octstr_destroy(pdu->u.handshake.certificate->x968_certificate);
break;
}
gw_free(pdu->u.handshake.certificate);
break;
case server_key_exchange:
destroy_param_spec(pdu->u.handshake.server_key_exchange->param_spec);
switch (client_key_exchange_algo) {
case rsa_anon:
destroy_rsa_pubkey(pdu->u.handshake.server_key_exchange->rsa_params);
break;
case dh_anon:
destroy_dh_pubkey(pdu->u.handshake.server_key_exchange->dh_params);
break;
case ecdh_anon:
destroy_ec_pubkey(pdu->u.handshake.server_key_exchange->ecdh_params);
break;
}
gw_free(pdu->u.handshake.server_key_exchange);
break;
case client_key_exchange:
switch (client_key_exchange_algo) {
case rsa:
case rsa_anon:
destroy_rsa_encrypted_secret(pdu->u.handshake.client_key_exchange->rsa_params);
break;
case dh_anon:
destroy_dh_pubkey(pdu->u.handshake.client_key_exchange->dh_anon_params);
break;
case ecdh_anon:
case ecdh_ecdsa:
destroy_ec_pubkey(pdu->u.handshake.client_key_exchange->ecdh_params);
break;
}
gw_free(pdu->u.handshake.client_key_exchange);
break;
case server_hello_done:
/* nothing to do here */
break;
}
break;
case Application_PDU:
octstr_destroy(pdu->u.application.data);
break;
}
gw_free(pdu);
}
/* This function will pack a list of WTLS PDUs into a single Octstr, and return
that Octstr. */
Octstr* wtls_pack_payloadlist (List* payloadlist) {
Octstr *returnData=0, *tempData1=0, *tempData2 = 0;
wtls_Payload* retrievedPDU;
/* Assert that our payloadlist is not NULL */
gw_assert (payloadlist != NULL);
/* Initialise our return Octstr */
returnData = octstr_create("");
/* While there are PDUs remaining in our list */
while (gwlist_len(payloadlist) > 0) {
/* Retrieve the next payload from the payloadlist */
retrievedPDU = (wtls_Payload*) gwlist_extract_first (payloadlist);
/* Pack the PDU */
tempData2 = wtls_payload_pack(retrievedPDU);
/* Shift the current stuff in returnData to a temporary pointer */
tempData1 = returnData;
/* Tack it onto our Octstr */
returnData = octstr_cat(tempData1, tempData2);
/* And now, we can get rid of both tempData1 and tempData2 */
octstr_destroy (tempData1);
octstr_destroy (tempData2);
}
/* Is the Octstr we finish with of length > 0? */
if (octstr_len(returnData) > 0) {
/* Return the Octstr */
return returnData;
}
/* Otherwise, return NULL */
return NULL;
}
/* This function will unpack an Octstr and return a list of all PDUs contained
within that Octstr. If the contents of the packet are garbled in some fashion,
and one packet fails to be decoded correctly, we will continue regardless, and
a partial list will be returned. NULL is returned if no PDUs can be successfully
decoded from the supplied data */
List* wtls_unpack_payloadlist (Octstr *data) {
List* payloadlist = NULL;
int offset = 0;
int dataLength = 0;
wtls_Payload* tempPayload;
/* Has somebody passed in an unpack of a null pointer ? */
gw_assert(data != NULL);
/* Initialise our list */
payloadlist = gwlist_create();
dataLength = octstr_len(data);
/* While offset is less than the size of the data */
while( offset < dataLength) {
debug("wtls:wtls_unpack_payloadlist",0,"Offset is now : %d", offset);
/* Unpack from the supplied offset. This will bump up the value of offset */
tempPayload = wtls_payload_unpack_from_offset (data, &offset);
/* If the packet returned is not NULL */
if (tempPayload != NULL) {
/* Add the returned packet to the current list of packets */
gwlist_append(payloadlist, (void*) tempPayload);
}
}
debug("wtls:wtls_unpack_payloadlist",0,"Finished, found %d PDUs", gwlist_len(payloadlist));
/* If the length of the list is greater than 0 */
if (gwlist_len(payloadlist) > 0) {
/* Return the List */
return payloadlist;
}
/* Otherwise return NULL */
return NULL;
}
/* This function tries to determine the length of the PDU at the start of the
supplied Octstr using (somewhat) intelligent means. If the packet is screwed
up in some fashion, returns length -1. Returns an int. */
int wtls_payload_guess_length(Octstr* data) {
int type = 0, lengthFlag = 0, lengthSize = 0, pdu_length = 0;
long lengthOffset = 1;
/* Is the fragment length indicator on? */
lengthFlag = octstr_get_bits(data, 0, 1);
if (lengthFlag) {
lengthSize = 2;
}
/* Is the sequence number indicator on? */
if (octstr_get_bits(data, 1, 1)) {
/* Yes, so hop over two extra bytes when reading the length */
lengthOffset += 2;
}
/* the message type */
type = octstr_get_bits(data, 4, 4);
/* If fragment length is turned on, jump to the necessary spot */
if (lengthFlag == 1) {
/* After this, lengthOffset + pdu_length == the total length of the PDU */
pdu_length = unpack_int16(data, &lengthOffset);
}
/* Oh great, so it's not switched on. How considerate. We'll have to make
a reasonable guess as to what it might be. */
else {
switch (type) {
case ChangeCipher_PDU:
/* They're really short */
pdu_length = 1;
break;
case Alert_PDU:
/* They're a bit longer */
pdu_length = 6;
break;
default:
/* Otherwise just give up and play dead */
pdu_length = -1;
break;
}
}
/* And that's the length of the contents, now just add the other doodads on */
if (pdu_length == -1) {
return -1;
}
else {
/* The pdu length, plus the sequence number, plus the length of the length value,
plus the actual header byte */
return (pdu_length + lengthOffset);
}
}
/* This function will unpack an Octstr, starting at the specified offset, and
return the corresponding wtls_PDU* which was generated from that offset. Offset
is changed during the running of this function, and ends up as the octet at the start of the
next pdu */
wtls_Payload* wtls_payload_unpack_from_offset (Octstr *data, int *offset) {
int guessedPayloadLength = 0;
int dataLength = 0;
Octstr* dataFromOffset = 0;
Octstr* dataFromOffsetToLength = 0;
wtls_Payload* returnPayload = 0;
/* This would be a sure sign of trouble */
gw_assert (offset != NULL);
gw_assert (data != NULL);
gw_assert (octstr_len(data) >= *offset);
dataLength = octstr_len(data);
/* First, we need to figure out how long a PDU starting from
the specified offset is going to be. We need to peek quickly into the
PDU to check this */
dataFromOffset = octstr_copy(data, *offset, dataLength);
guessedPayloadLength = wtls_payload_guess_length(dataFromOffset);
/* Ooops. Something's wrong. This requested PDU is screwed up. */
if (guessedPayloadLength == -1) {
*offset = dataLength;
return NULL;
}
/* Quit if we discover that the PDU length plus the requested offset is
larger than the length of the data supplied - this would mean that we
would overrun our data, and therefore something is corrupt in this PDU.
Set the offset as the data length, which will indicate we've gone as far
as we can */
if ((*offset + guessedPayloadLength) > dataLength) {
*offset = dataLength;
return NULL;
}
/* If we pass that test, set offset to the correct return value */
*offset += guessedPayloadLength;
/* Copy the octstr again, so that we end up with an octstr containing
just the PDU we want */
dataFromOffsetToLength = octstr_copy(dataFromOffset, 0, guessedPayloadLength);
/* Submit that octstr to the wtls_message_unpack function */
returnPayload = wtls_payload_unpack(dataFromOffsetToLength);
/* Test to make sure the returned PDU is good */
if (returnPayload != NULL) {
/* And return the PDU to our caller */
return returnPayload;
}
/* Otherwise return NULL */
return NULL;
}
wtls_Payload *wtls_payload_unpack(Octstr *data) {
wtls_Payload *payload = NULL;
Octstr *buffer;
long bitpos = 0, charpos = 0;
int msg_length;
gw_assert(data != NULL);
payload = gw_malloc(sizeof(wtls_Payload));
/* the record field length flag */
payload->rlen = octstr_get_bits(data, bitpos, 1);
bitpos += 1;
/* the sequence number flag */
payload->seqnum = octstr_get_bits(data, bitpos, 1);
bitpos += 1;
/* the cipher usage flag */
payload->cipher = octstr_get_bits(data, bitpos, 1);
bitpos += 1;
/* the reserved bit */
payload->reserved = octstr_get_bits(data, bitpos, 1);
bitpos += 1;
/* the message type */
payload->type = octstr_get_bits(data, bitpos, 4);
bitpos += 4;
charpos += 1;
/* get the sequence number if present */
if(payload->seqnum) {
seqnum = unpack_int16(data, &charpos);
}
/* get the WTLS plaintext length if present */
if(payload->rlen) {
msg_length = unpack_int16(data, &charpos);
}
/* the part of data that has just been processed is not
needed anymore. We delete it. What is left of data is
the payload. */
octstr_delete(data, 0, charpos);
payload->data = data;
return payload;
}
void *wtls_payloadlist_destroy(List* payloadList) {
wtls_Payload* currentPayload;
int listLen, i;
listLen = gwlist_len(payloadList);
for( i=0; idata != NULL);
pdu = gw_malloc(sizeof(*pdu));
pdu->type = payload->type;
pdu->reserved = payload->reserved;
pdu->cipher = payload->cipher;
pdu->seqnum = payload->seqnum;
pdu->rlen = payload->rlen;
/* is the PDU encrypted ? */
/*
if(pdu->cipher) {
buffer = wtls_decrypt(payload->data, wtls_machine);
}
else {
*/
buffer = payload->data;
/*
}
*/
switch (pdu->type) {
case ChangeCipher_PDU:
pdu->u.cc.change = octstr_get_char(buffer, charpos);
charpos += 1;
break;
case Alert_PDU:
pdu->u.alert.level = octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.alert.desc = octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.alert.chksum = unpack_octstr_fixed(buffer, &charpos, 4);
break;
case Handshake_PDU:
pdu->u.handshake.msg_type = octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.handshake.length = unpack_int16(buffer, &charpos);
switch (pdu->u.handshake.msg_type) {
case hello_request:
break;
case client_hello:
pdu->u.handshake.client_hello = (ClientHello *)gw_malloc(sizeof(ClientHello));
pdu->u.handshake.client_hello->clientversion = octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.handshake.client_hello->random = unpack_random(buffer, &charpos);
pdu->u.handshake.client_hello->session_id = unpack_octstr(buffer, &charpos);
/* pack the list of keys */
pdu->u.handshake.client_hello->client_key_ids = unpack_key_list(buffer, &charpos);
pdu->u.handshake.client_hello->trusted_key_ids = unpack_key_list(buffer, &charpos);
/* pack the list of CipherSuites */
pdu->u.handshake.client_hello->ciphersuites = unpack_ciphersuite_list(buffer, &charpos);
/* CompressionMethods */
pdu->u.handshake.client_hello->comp_methods = unpack_compression_method_list(buffer, &charpos);
pdu->u.handshake.client_hello->snmode = octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.handshake.client_hello->krefresh = octstr_get_char(buffer, charpos);
charpos += 1;
break;
case server_hello:
pdu->u.handshake.server_hello = (ServerHello *)gw_malloc(sizeof(ServerHello));
pdu->u.handshake.server_hello->serverversion = octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.handshake.server_hello->random = unpack_random(buffer, &charpos);
pdu->u.handshake.server_hello->session_id = unpack_octstr(buffer, &charpos);
charpos += 1;
pdu->u.handshake.server_hello->client_key_id
= octstr_get_char(buffer, charpos);
charpos += 1;
/* CypherSuite */
pdu->u.handshake.server_hello->ciphersuite->bulk_cipher_algo
= octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.handshake.server_hello->ciphersuite->mac_algo
= octstr_get_char(buffer, charpos);
charpos += 1;
/* CompressionMethod */
pdu->u.handshake.server_hello->comp_method = octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.handshake.server_hello->snmode = octstr_get_char(buffer, charpos);
charpos += 1;
pdu->u.handshake.server_hello->krefresh = octstr_get_char(buffer, charpos);
charpos += 1;
break;
case certificate:
pdu->u.handshake.certificate = (Certificate *)gw_malloc(sizeof(Certificate));
pdu->u.handshake.certificate->certificateformat = octstr_get_char(buffer, charpos);
charpos += 1;
switch (pdu->u.handshake.certificate->certificateformat) {
case WTLSCert:
pdu->u.handshake.certificate->wtls_certificate = unpack_wtls_certificate(buffer, &charpos);
break;
case X509Cert:
pdu->u.handshake.certificate->x509_certificate = unpack_octstr16(buffer, &charpos);
break;
case X968Cert:
pdu->u.handshake.certificate->x968_certificate = unpack_octstr16(buffer, &charpos);
break;
}
break;
case server_key_exchange:
pdu->u.handshake.server_key_exchange = (ServerKeyExchange *)gw_malloc(sizeof(ServerKeyExchange));
/* unpack the ParameterSpecifier and ParameterSet*/
pdu->u.handshake.server_key_exchange->param_spec
= unpack_param_spec(buffer, &charpos);
switch (client_key_exchange_algo) {
case rsa_anon:
pdu->u.handshake.server_key_exchange->rsa_params
= unpack_rsa_pubkey(buffer, &charpos);
break;
case dh_anon:
pdu->u.handshake.server_key_exchange->dh_params
= unpack_dh_pubkey(buffer, &charpos);
break;
case ecdh_anon:
pdu->u.handshake.server_key_exchange->ecdh_params
= unpack_ec_pubkey(buffer, &charpos);
break;
}
break;
case client_key_exchange:
pdu->u.handshake.client_key_exchange = (ClientKeyExchange *)gw_malloc(sizeof(ClientKeyExchange));
switch (client_key_exchange_algo) {
case rsa:
case rsa_anon:
pdu->u.handshake.client_key_exchange->rsa_params
= unpack_rsa_encrypted_secret(buffer, &charpos);
break;
case dh_anon:
pdu->u.handshake.client_key_exchange->dh_anon_params
= unpack_dh_pubkey(buffer, &charpos);
break;
case ecdh_anon:
case ecdh_ecdsa:
pdu->u.handshake.client_key_exchange->ecdh_params
= unpack_ec_pubkey(buffer, &charpos);
break;
}
break;
case server_hello_done:
/* empty */
break;
case finished:
pdu->u.handshake.finished = (Finished *)gw_malloc(sizeof(Finished));
pdu->u.handshake.finished->verify_data
= unpack_octstr_fixed(buffer, &charpos, 12);
octstr_dump(pdu->u.handshake.finished->verify_data, 0);
break;
}
break;
case Application_PDU:
/* application message */
pdu->u.application.data = octstr_duplicate(buffer);
break;
default:
debug("wap.wtls", 0, "%*sPDU: ", 0, "");
octstr_dump(buffer, 0);
panic(0, "Unpacking unknown WTLS PDU type %ld", (long) pdu->type);
}
return pdu;
}
Octstr *wtls_payload_pack(wtls_Payload *payload) {
Octstr *data;
long bitpos, charpos;
long messageSizePos, sizepos;
/* Used for length calculations */
int size;
/* We rely on octstr_set_bits to lengthen our octstr as needed. */
data = octstr_create("");
bitpos = 0;
charpos = 0;
sizepos = 0;
/* the record field length flag - always present*/
octstr_set_bits(data, bitpos, 1, 1);
bitpos += 1;
/* the sequence number flag */
octstr_set_bits(data, bitpos, 1, payload->seqnum);
bitpos += 1;
/* the cipher usage flag */
octstr_set_bits(data, bitpos, 1, payload->cipher);
bitpos += 1;
/* the reserved bit */
octstr_set_bits(data, bitpos, 1, payload->reserved);
bitpos += 1;
/* set the message type */
octstr_set_bits(data, bitpos, 4, payload->type);
bitpos += 4;
charpos += 1;
/* set the sequence number if present */
if(payload->seqnum) {
charpos = pack_int16(data, charpos, payload->seqnum);
}
/* set the WTLS length */
charpos = pack_int16(data, charpos, payload->rlen);
/* append the data from the wtls_PDU */
octstr_insert(data, payload->data, octstr_len(data));
return data;
}
wtls_Payload *wtls_pdu_pack(wtls_PDU *pdu, WTLSMachine* wtls_machine) {
Octstr *data, *buffer, *encryptedbuffer;
wtls_Payload *payload;
long bitpos, charpos;
long messageSizePos, sizepos;
/* Used for length calculations */
int size, recordType;
/* create the wtls_PDU */
payload = (wtls_Payload *)gw_malloc(sizeof(wtls_Payload));
payload->type = pdu->type;
payload->reserved = pdu->reserved;
payload->cipher = pdu->cipher;
payload->seqnum = pdu->seqnum;
/* We rely on octstr_set_bits to lengthen our octstr as needed. */
data = octstr_create("");
buffer = octstr_create("");
bitpos = 0;
charpos = 0;
sizepos = 0;
switch (pdu->type) {
case ChangeCipher_PDU:
octstr_append_char(buffer, pdu->u.cc.change);
charpos += 1;
break;
case Alert_PDU:
octstr_append_char(buffer, pdu->u.alert.level);
charpos += 1;
octstr_append_char(buffer, pdu->u.alert.desc);
charpos += 1;
charpos = pack_octstr_fixed(buffer, charpos, pdu->u.alert.chksum);
charpos += 1;
break;
case Handshake_PDU:
octstr_append_char(buffer, pdu->u.handshake.msg_type);
charpos += 1;
/* Save the location of the message size */
messageSizePos = charpos;
charpos = pack_int16 (buffer, charpos, pdu->u.handshake.length);
switch (pdu->u.handshake.msg_type) {
case hello_request:
break;
case client_hello:
octstr_append_char(buffer, pdu->u.handshake.client_hello->clientversion);
charpos += 1;
charpos = pack_random(buffer, charpos, pdu->u.handshake.client_hello->random);
octstr_append_char(buffer, octstr_len(
pdu->u.handshake.client_hello->session_id));
charpos += 1;
charpos = pack_octstr(buffer, charpos, pdu->u.handshake.client_hello->session_id);
/* pack the list of keys */
charpos = pack_key_list(buffer, charpos,
pdu->u.handshake.client_hello->client_key_ids);
charpos = pack_key_list(buffer, charpos,
pdu->u.handshake.client_hello->trusted_key_ids);
/* pack the list of CipherSuites */
charpos = pack_ciphersuite_list(buffer, charpos,
pdu->u.handshake.client_hello->ciphersuites);
/* CompressionMethods */
charpos = pack_compression_method_list(buffer, charpos,
pdu->u.handshake.client_hello->comp_methods);
octstr_append_char(buffer, pdu->u.handshake.client_hello->snmode);
charpos += 1;
octstr_append_char(buffer, pdu->u.handshake.client_hello->krefresh);
charpos += 1;
break;
case server_hello:
octstr_append_char(buffer, pdu->u.handshake.server_hello->serverversion);
charpos += 1;
charpos = pack_random(buffer, charpos, pdu->u.handshake.server_hello->random);
charpos = pack_octstr(buffer, charpos, pdu->u.handshake.server_hello->session_id);
charpos += 1;
octstr_append_char(buffer, pdu->u.handshake.server_hello->
client_key_id);
charpos += 1;
/* CypherSuite */
octstr_append_char(buffer, pdu->u.handshake.server_hello->
ciphersuite->bulk_cipher_algo);
charpos += 1;
octstr_append_char(buffer, pdu->u.handshake.server_hello->
ciphersuite->mac_algo);
charpos += 1;
/* CompressionMethod */
octstr_append_char(buffer, pdu->u.handshake.server_hello->comp_method);
charpos += 1;
octstr_append_char(buffer, pdu->u.handshake.server_hello->snmode);
charpos += 1;
octstr_append_char(buffer, pdu->u.handshake.server_hello->krefresh);
charpos += 1;
break;
case certificate:
octstr_append_char(buffer, pdu->u.handshake.certificate->certificateformat);
charpos += 1;
switch (pdu->u.handshake.certificate->certificateformat) {
case WTLSCert:
charpos = pack_wtls_certificate(buffer, charpos, pdu->u.handshake.certificate->wtls_certificate);
break;
case X509Cert:
charpos = pack_octstr16(buffer, charpos, pdu->u.handshake.certificate->x509_certificate);
break;
case X968Cert:
charpos = pack_octstr16(buffer, charpos, pdu->u.handshake.certificate->x968_certificate);
break;
}
break;
case server_key_exchange:
debug("wtls: ", 0,"Packing ServerKeyExchange");
/* pack the ParameterSpecifier */
charpos = pack_param_spec(buffer, charpos, pdu->u.handshake.server_key_exchange->param_spec);
switch (client_key_exchange_algo) {
case rsa_anon:
charpos = pack_rsa_pubkey(buffer, charpos, pdu->u.handshake.server_key_exchange->rsa_params);
break;
case dh_anon:
charpos = pack_dh_pubkey(buffer, charpos, pdu->u.handshake.server_key_exchange->dh_params);
break;
case ecdh_anon:
charpos = pack_ec_pubkey(buffer, charpos, pdu->u.handshake.server_key_exchange->ecdh_params);
break;
}
break;
case client_key_exchange:
switch (client_key_exchange_algo) {
case rsa:
case rsa_anon:
charpos = pack_rsa_encrypted_secret(buffer, charpos, pdu->u.handshake.client_key_exchange->rsa_params);
break;
case dh_anon:
charpos = pack_dh_pubkey(buffer, charpos, pdu->u.handshake.client_key_exchange->dh_anon_params);
break;
case ecdh_anon:
case ecdh_ecdsa:
charpos = pack_ec_pubkey(buffer, charpos, pdu->u.handshake.client_key_exchange->ecdh_params);
break;
}
break;
case server_hello_done:
/* empty */
break;
case finished:
charpos = pack_octstr_fixed(buffer, charpos, pdu->u.handshake.finished->verify_data);
debug("wtls", 0, "verify_data (in pack)");
octstr_dump(pdu->u.handshake.finished->verify_data,0 );
break;
}
/* Change the length */
size = octstr_len(buffer) - messageSizePos - 2;
debug("wtls_msg.c:length",0,"Setting msg size to : %d",size);
octstr_set_char(buffer, messageSizePos, (size & 0xFF00) >> 8);
messageSizePos += 1;
octstr_set_char(buffer, messageSizePos, (size & 0x00FF));
/* we keep the handshake data to create the Finished PDU */
octstr_append(wtls_machine->handshake_data, buffer);
break;
case Application_PDU:
/* application message */
charpos += pack_octstr(data, charpos, pdu->u.application.data);
break;
default:
panic(0, "Packing unknown WTLS PDU type %ld", (long) pdu->type);
}
/* encrypt the buffer if needed */
if(pdu->cipher) {
/* the MAC is calculated with the record type so we need it now */
recordType = 1 << 7; /* length, always present */
recordType |= pdu->seqnum << 6;
recordType |= pdu->cipher << 5;
recordType |= pdu->reserved << 4;
recordType |= pdu->type;
encryptedbuffer = wtls_encrypt(buffer, wtls_machine, recordType);
payload->data = encryptedbuffer;
}
else {
payload->data = buffer;
}
payload->rlen = octstr_len(payload->data);
debug("wtls", 0, "Packed PDU Length: %d", payload->rlen);
return payload;
}
void wtls_pdu_dump(wtls_PDU *pdu, int level) {
unsigned char *dbg = "wap.wtls";
/* the message type */
debug(dbg, 0, "%*sPDU type: %p", level, "", pdu->type);
/* the reserved bit */
debug(dbg, 0, "%*sReserved bit: %p", level, "", pdu->reserved);
/* cipher usage flag */
debug(dbg, 0, "%*sCipher in use: %p", level, "", pdu->cipher);
/* the sequence number flag */
debug(dbg, 0, "%*sSequence number in use: %p", level, "", pdu->seqnum);
/* the record field length flag */
debug(dbg, 0, "%*sRecord field length present: %p", level, "", pdu->rlen);
switch (pdu->type) {
case ChangeCipher_PDU:
debug(dbg, 0, "%*sChangeCipher:", level, "");
debug(dbg, 0, "%*sChange: %d", level+1, "", pdu->u.cc.change);
break;
case Alert_PDU:
debug(dbg, 0, "%*sAlert:", level, "");
debug(dbg, 0, "%*sLevel: %p", level+1, "", pdu->u.alert.level);
debug(dbg, 0, "%*sDescription: %d", level+1, "", pdu->u.alert.desc);
debug(dbg, 0, "%*sChecksum: %p", level+1, "", pdu->u.alert.chksum);
break;
case Handshake_PDU:
debug(dbg, 0, "%*sHandshake:", level, "");
debug(dbg, 0, "%*sMessage Type: %d", level+1, "", pdu->u.handshake.msg_type);
debug(dbg, 0, "%*sLength: %d", level+1, "", pdu->u.handshake.length);
switch (pdu->u.handshake.msg_type) {
case hello_request:
debug(dbg, 0, "%*sHelloRequest.", level, "");
break;
case client_hello:
debug(dbg, 0, "%*sClientHello :", level, "");
debug(dbg, 0, "%*sClient version: %d", level+1, "", pdu->u.handshake.client_hello->clientversion);
debug(dbg, 0, "%*sRandom:", level+1, "");
dump_random(dbg, level+2,
pdu->u.handshake.client_hello->random);
debug(dbg, 0, "%*sSessionId: ", level, "");
octstr_dump(pdu->u.handshake.client_hello->session_id, level + 2);
/* pack the list of keys */
debug(dbg, 0, "%*sClient Key IDs: ", level+1, "");
dump_key_list(dbg, level+2,
pdu->u.handshake.client_hello->client_key_ids);
debug(dbg, 0, "%*sTrusted Key IDs: ", level+1, "");
dump_key_list(dbg, level+2,
pdu->u.handshake.client_hello->trusted_key_ids);
/* pack the list of CipherSuites */
debug(dbg, 0, "%*sCipherSuite List: ", level+1, "");
dump_ciphersuite_list(dbg, level+2,
pdu->u.handshake.client_hello->ciphersuites);
/* CompressionMethods */
debug(dbg, 0, "%*sCompression Method List: ", level+1, "");
dump_compression_method_list(dbg, level+2,
pdu->u.handshake.client_hello->comp_methods);
debug(dbg, 0, "%*sSeq Number Mode: %d", level+1, "", pdu->u.handshake.client_hello->snmode);
debug(dbg, 0, "%*sKey Refresh: %p", level+1, "", pdu->u.handshake.client_hello->krefresh);
break;
case server_hello:
debug(dbg, 0, "%*sServerHello :", level, "");
debug(dbg, 0, "%*sServer version: %d", level+1, "", pdu->u.handshake.server_hello->serverversion);
debug(dbg, 0, "%*sRandom:", level+1, "");
dump_random(dbg, level+2,
pdu->u.handshake.server_hello->random);
debug(dbg, 0, "%*sSession ID: %d", level+1, "", pdu->u.handshake.server_hello->session_id);
debug(dbg, 0, "%*sClient Key ID: %p", level+1, "", pdu->u.handshake.server_hello->client_key_id);
/* CypherSuite */
debug(dbg, 0, "%*sBulk Cipher Algo: %p", level+1, "", pdu->u.handshake.server_hello->ciphersuite->bulk_cipher_algo);
debug(dbg, 0, "%*sMAC Algo: %p", level+1, "", pdu->u.handshake.server_hello->ciphersuite->mac_algo);
/* CompressionMethod */
debug(dbg, 0, "%*sCompression Method: %p", level+1, "", pdu->u.handshake.server_hello->comp_method);
debug(dbg, 0, "%*sSeq Number Mode: %p", level+1, "", pdu->u.handshake.server_hello->snmode);
debug(dbg, 0, "%*sKey Refresh: %p", level+1, "", pdu->u.handshake.server_hello->krefresh);
break;
case certificate:
debug(dbg, 0, "%*sCertificate :", level, "");
debug(dbg, 0, "%*sCertificate Format: %p", level+1, "", pdu->u.handshake.certificate->certificateformat);
switch (pdu->u.handshake.certificate->certificateformat) {
case WTLSCert:
debug(dbg, 0, "%*sWTLS Certificate: %p", level+1, "");
dump_wtls_certificate(dbg, level+2, pdu->u.handshake.certificate->wtls_certificate);
break;
case X509Cert:
debug(dbg, 0, "%*sX509 Certificate: %p", level+1, "");
octstr_dump(pdu->u.handshake.certificate->x509_certificate, level+2);
break;
case X968Cert:
debug(dbg, 0, "%*sX968 Certificate: %p", level+1, "");
octstr_dump(pdu->u.handshake.certificate->x968_certificate, level+2);
break;
}
break;
case server_key_exchange:
debug(dbg, 0, "%*sServerKeyExchange :", level, "");
/* ParameterSpecifier */
debug(dbg, 0, "%*sParameter Index: %p", level+1, "", pdu->u.handshake.server_key_exchange->param_spec->param_index);
if(pdu->u.handshake.server_key_exchange->param_spec->param_index == 255) {
/* ParameterSet */
debug(dbg, 0, "%*sParameter Set: %p", level+1, "", pdu->u.handshake.server_key_exchange->param_spec->param_set);
}
switch (client_key_exchange_algo) {
case rsa_anon:
dump_rsa_pubkey(dbg, level+1, pdu->u.handshake.server_key_exchange->rsa_params);
break;
case dh_anon:
dump_dh_pubkey(dbg, level+1, pdu->u.handshake.server_key_exchange->dh_params);
break;
case ecdh_anon:
dump_ec_pubkey(dbg, level+1, pdu->u.handshake.server_key_exchange->ecdh_params);
break;
}
break;
case client_key_exchange:
debug(dbg, 0, "%*sClientKeyExchange :", level, "");
switch (client_key_exchange_algo) {
case rsa:
case rsa_anon:
dump_rsa_encrypted_secret(dbg, level+1, pdu->u.handshake.client_key_exchange->rsa_params);
break;
case dh_anon:
dump_dh_pubkey(dbg, level+1, pdu->u.handshake.client_key_exchange->dh_anon_params);
break;
case ecdh_anon:
case ecdh_ecdsa:
dump_ec_pubkey(dbg, level+1, pdu->u.handshake.client_key_exchange->ecdh_params);
break;
}
break;
case server_hello_done:
debug(dbg, 0, "%*sClientHelloDone.", level, "");
/* empty */
break;
case finished:
debug(dbg, 0, "%*sFinished :", level, "");
debug(dbg, 0, "%*sverify_data :", level+1, "");
octstr_dump(pdu->u.handshake.finished->verify_data, level+2);
break;
}
break;
case Application_PDU:
debug(dbg, 0, "%*sApplication :", level, "");
/* application message */
octstr_dump(pdu->u.application.data, level+1);
break;
default:
debug(dbg, 0, "%*sWTLS PDU at %p:", level, "", (void *)pdu);
debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
}
}
#endif
gateway-1.4.3/wap/wtls.h 0000644 0001750 0001750 00000010453 11132672004 014146 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* WTLS Server Header
*
* Nick Clarey
*/
#ifndef WTLS_H
#define WTLS_H
typedef struct WTLSMachine WTLSMachine;
#include "gw/msg.h"
//#include "gw/wapbox.h"
#include "wap/wap_events.h"
#include "wap/wtls_pdu.h"
/*
* WTLS Server machine states and WTLS machine.
* See file wtls_state-decl.h for comments. Note that we must define macro
* ROW to produce an empty string.
*/
enum serv_states {
#define STATE_NAME(state) state,
#define ROW(state, event, condition, action, next_state)
#include "wtls_state-decl.h"
serv_states_count
};
typedef enum serv_states serv_states;
/*
* See files wtls_machine-decl.h for comments. We define one macro for
* every separate type.
*/
struct WTLSMachine {
unsigned long mid;
#define ENUM(name) serv_states name;
#define ADDRTUPLE(name) WAPAddrTuple *name;
#define INTEGER(name) int name;
#define OCTSTR(name) Octstr *name;
#define MACHINE(field) field
#define PDULIST(name) List *name;
#include "wtls_machine-decl.h"
};
/*
* Initialize the WTLS server.
*/
void wtls_init(void);
/*
* Shut down the WTLS server machines. MUST be called after the subsystem isn't
* used anymore.
*/
void wtls_shutdown(void);
/*
* Transfers control of an event to the WTLS server machine subsystem.
*/
void wtls_dispatch_event(WAPEvent *event);
/*
* Handles possible concatenated messages. Returns a list of wap events.
* Real unpacking is done by an internal function.
*/
WAPEvent *wtls_unpack_wdp_datagram(Msg *msg);
int wtls_get_address_tuple(long mid, WAPAddrTuple **tuple);
#endif
gateway-1.4.3/wap/wtls_pdusupport.h 0000644 0001750 0001750 00000016712 11132672002 016455 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
#ifndef PDUSUPPORT_H
#define PDUSUPPORT_H
int pack_int16(Octstr *data, long charpos, int i);
int pack_int32(Octstr *data, long charpos, long i);
int pack_octstr(Octstr *data, long charpos, Octstr *opaque);
int pack_octstr16(Octstr *data, long charpos, Octstr *opaque);
int pack_octstr_fixed(Octstr *data, long charpos, Octstr *opaque);
int pack_random(Octstr *data, long charpos, Random *random);
int pack_dhparams(Octstr *data, long charpos, DHParameters *dhparams);
int pack_ecparams(Octstr *data, long charpos, ECParameters *ecparams);
int pack_param_spec(Octstr *data, long charpos, ParameterSpecifier *pspec);
int pack_public_key(Octstr *data, long charpos, PublicKey *key, PublicKeyType key_type);
int pack_rsa_pubkey(Octstr *data, long charpos, RSAPublicKey *key);
int pack_dh_pubkey(Octstr *data, long charpos, DHPublicKey *key);
int pack_ec_pubkey(Octstr *data, long charpos, ECPublicKey *key);
int pack_rsa_secret(Octstr *data, long charpos, RSASecret *secret);
int pack_rsa_encrypted_secret(Octstr *data, long charpos, RSAEncryptedSecret *secret);
int pack_key_exchange_id(Octstr *data, long charpos, KeyExchangeId *keyexid);
int pack_array(Octstr *data, long charpos, List *array);
int pack_key_list(Octstr *data, long charpos, List *key_list);
int pack_ciphersuite_list(Octstr *data, long charpos, List *ciphersuites);
int pack_compression_method_list(Octstr *data, long charpos, List *compmethod_list);
int pack_identifier(Octstr *data, long charpos, Identifier *ident);
int pack_signature(Octstr *data, long charpos, Signature *sig);
int pack_wtls_certificate(Octstr *data, long charpos, WTLSCertificate *cert);
int unpack_int16(Octstr *data, long *charpos);
long unpack_int32(Octstr *data, long *charpos);
Octstr * unpack_octstr(Octstr *data, long *charpos);
Octstr * unpack_octstr16(Octstr *data, long *charpos);
Octstr * unpack_octstr_fixed(Octstr *data, long *charpos, long length);
Random * unpack_random(Octstr *data, long *charpos);
DHParameters * unpack_dhparams(Octstr *data, long *charpos);
ECParameters * unpack_ecparams(Octstr *data, long *charpos);
ParameterSpecifier * unpack_param_spec(Octstr *data, long *charpos);
PublicKey * unpack_public_key(Octstr *data, long *charpos, PublicKeyType key_type);
RSAPublicKey * unpack_rsa_pubkey(Octstr *data, long *charpos);
DHPublicKey * unpack_dh_pubkey(Octstr *data, long *charpos);
ECPublicKey * unpack_ec_pubkey(Octstr *data, long *charpos);
RSASecret * unpack_rsa_secret(Octstr *data, long *charpos);
RSAEncryptedSecret * unpack_rsa_encrypted_secret(Octstr *data, long *charpos);
KeyExchangeId * unpack_key_exchange_id(Octstr *data, long *charpos);
List * unpack_array(Octstr *data, long *charpos);
List * unpack_ciphersuite_list(Octstr *data, long *charpos);
List * unpack_key_list(Octstr *data, long *charpos);
List * unpack_compression_method_list(Octstr *data, long *charpos);
Identifier * unpack_identifier(Octstr *data, long *charpos);
Signature * unpack_signature(Octstr *data, long *charpos);
WTLSCertificate * unpack_wtls_certificate(Octstr *data, long *charpos);
void dump_int16(unsigned char *dbg, int level, int i);
void dump_int32(unsigned char *dbg, int level, long i);
void dump_octstr(unsigned char *dbg, int level, Octstr *opaque);
void dump_octstr16(unsigned char *dbg, int level, Octstr *opaque);
void dump_octstr_fixed(unsigned char *dbg, int level, Octstr *opaque);
void dump_random(unsigned char *dbg, int level, Random *random);
void dump_dhparams(unsigned char *dbg, int level, DHParameters *dhparams);
void dump_ecparams(unsigned char *dbg, int level, ECParameters *ecparams);
void dump_param_spec(unsigned char *dbg, int level, ParameterSpecifier *pspec);
void dump_public_key(unsigned char *dbg, int level, PublicKey *key, PublicKeyType key_type);
void dump_rsa_pubkey(unsigned char *dbg, int level, RSAPublicKey *key);
void dump_dh_pubkey(unsigned char *dbg, int level, DHPublicKey *key);
void dump_ec_pubkey(unsigned char *dbg, int level, ECPublicKey *key);
void dump_rsa_secret(unsigned char *dbg, int level, RSASecret *secret);
void dump_rsa_encrypted_secret(unsigned char *dbg, int level, RSAEncryptedSecret *secret);
void dump_key_exchange_id(unsigned char *dbg, int level, KeyExchangeId *keyexid);
void dump_array(unsigned char *dbg, int level, List *array);
void dump_key_list(unsigned char *dbg, int level, List *key_list);
void dump_ciphersuite_list(unsigned char *dbg, int level, List *ciphersuites);
void dump_compression_method_list(unsigned char *dbg, int level, List *compmethod_list);
void dump_identifier(unsigned char *dbg, int level, Identifier *ident);
void dump_signature(unsigned char *dbg, int level, Signature *sig);
void dump_wtls_certificate(unsigned char *dbg, int level, WTLSCertificate *cert);
void destroy_rsa_pubkey(RSAPublicKey *key);
void destroy_array(List *array);
void destroy_identifier(Identifier *ident);
#endif
gateway-1.4.3/wap/wap.h 0000644 0001750 0001750 00000022173 11132672003 013745 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wap.h - public interface to WAP protocol library
*
* The WAP protocol library consists of separate layers, which each run
* in their own thread. The layers are normally used together and will
* communicate with each other, but they can be used separately by
* specialized applications.
*
* Communication between layers is done by sending WAPEvent structures.
* These events are passed to dispatch functions. Each layer has its
* own dispatch function which is responsible for queueing the event
* for that layer.
*
* The application using this library has to provide an application layer
* and a datagram layer. These layers do not have to be implemented in
* any particular way and do not have to run in their own threads, but
* they do have to provide dispatch functions.
*
* In general, if a layer receives an event that it does not know how
* to handle, it will report this and ignore the event.
*/
#ifndef WAP_H
#define WAP_H
#include "wap_events.h"
#include "wap_addr.h"
typedef void wap_dispatch_func_t(WAPEvent *event);
/*
* Generic dispatch function that takes T_DUnitdata_Ind events and
* figures out to which layer they should be sent, by recognizing
* well-known port numbers and by inspecting the datagram contents.
* It also unpacks WTP events before dispatching, so that the WTP
* thread is not burdened by this.
*/
void wap_dispatch_datagram(WAPEvent *event);
/*
* Generic startup function that initializes all the layers and
* chains their dispatch functions together.
*/
void wap_init(wap_dispatch_func_t *datagram_dispatch,
wap_dispatch_func_t *application_dispatch);
/*
* Undoes what wap_init did.
*/
void wap_shutdown(void);
/*
* Datagram layer
*
* This layer is not provided by libwap itself. The application is
* expected to create one, by:
* - providing a dispatch function that takes T_DUnitdata_Req
* events (outgoing datagrams)
* - passing incoming datagrams to the right layer, either by
* calling the layer's dispatch function directly or by calling
* wap_dispatch_datagram().
*/
/*
* Transaction layer, responder
*
* This layer implements the Responder side of WTP.
* Its dispatch function takes events of these types:
*
* RcvInvoke, RcvAck, RcvAbort, RcvErrorPDU,
* TR_Invoke_Res, TR_Result_Req, TR_Abort_Req,
* TimerTO_A, TimerTO_R, TimerTO_W
*
* FIXME It also takes T_DUnitdata_Ind events, which it will unpack into one
* of the Rcv* events and then process.
*
* This layer will dispatch T_DUnitdata_Req events to the datagram layer,
* and these event types to the session layer:
*
* TR_Invoke_Ind, TR_Result_Cnf, TR_Abort_Ind
*
* Timer_freq is the timer 'tick' used. All wtp responder timers are
* multiplies of this value.
*/
void wtp_resp_init(wap_dispatch_func_t *datagram_dispatch,
wap_dispatch_func_t *session_dispatch,
wap_dispatch_func_t *push_dispatch,
long timer_freq);
void wtp_resp_dispatch_event(WAPEvent *event);
void wtp_resp_shutdown(void);
/*
* Transaction layer, initiator
*
* This layer implements the Initiator side of WTP.
* FIXME Currently only class 0 and 1 are implemented.
* Its dispatch function takes events of these types:
*
* RcvAck, RcvAbort, RcvErrorPDU
* TR_Invoke_Req, TR_Abort_Req
* TimerTO_R
*
* FIXME It also takes T_DUnitdata_Ind events, which it will unpack into one
* of the Rcv* events and then process.
*
* This layer will dispatch T_DUnitdata_Req events to the datagram layer,
* and these event types to the session layer:
*
* TR_Invoke_Cnf, TR_Abort_Ind
*
* Timer_freq is a timer 'tick'. All initiator timer values are multiplies
* of it.
*/
void wtp_initiator_init(wap_dispatch_func_t *datagram_dispatch,
wap_dispatch_func_t *session_dispatch,
long timer_freq);
void wtp_initiator_dispatch_event(WAPEvent *event);
void wtp_initiator_shutdown(void);
/*
* Session layer, connectionless mode
*
* This layer implements Connectionless WSP.
* FIXME Currently only the server side is implemented.
* Its dispatch function takes events of these types:
*
* T_DUnitdata_Ind
* S_Unit_MethodResult_Req
*
* This layer will dispatch T_DUnitdata_Req events to the datagram layer,
* and S_Unit_MethodInvoke_Ind events to the application layer.
*/
void wsp_unit_init(wap_dispatch_func_t *datagram_dispatch,
wap_dispatch_func_t *application_dispatch);
void wsp_unit_dispatch_event(WAPEvent *event);
void wsp_unit_shutdown(void);
/*
* Session layer, connection-oriented mode, server side
*
* This layer implements the server side of connection-oriented WSP.
* FIXME Not all defined service primitives are supported yet.
* Its dispatch function takes events of these types:
*
* TR_Invoke_Ind, TR_Result_Cnf, TR_Abort_Ind
* S_Connect_Res, S_Resume_Res
* S_MethodInvoke_Res, S_MethodResult_Res
* Disconnect_Event, Suspend_Event (internal)
*
* This layer will dispatch events of these types to the application layer:
*
* S_Connect_Ind, S_Disconnect_Ind,
* S_Suspend_Ind, S_Resume_Ind,
* S_MethodInvoke_Ind, S_MethodResult_Cnf, S_MethodAbort_Ind
*
* and events of these types to the WTP Responder layer:
*
* TR_Invoke_Res, TR_Result_Req, TR_Abort_Req
*
* and events of these types to the WTP Initiator layer:
*
* (none yet)
*/
void wsp_session_init(wap_dispatch_func_t *responder_dispatch,
wap_dispatch_func_t *initiator_dispatch,
wap_dispatch_func_t *application_dispatch,
wap_dispatch_func_t *ota_dispatch);
void wsp_session_dispatch_event(WAPEvent *event);
void wsp_session_shutdown(void);
/*
* Session layer, connection-oriented mode, client side
*
* FIXME Not implemented yet.
*/
void wsp_push_client_init(wap_dispatch_func_t *dispatch_self,
wap_dispatch_func_t *dispatch_wtp_resp);
void wsp_push_client_shutdown(void);
void wsp_push_client_dispatch_event(WAPEvent *e);
/*
* Application layer
*
* This layer is not provided by libwap itself. The application is
* expected to create one, by providing a dispatch function to the
* session layer that takes events of these types:
*
* S_Connect_Ind, S_Disconnect_Ind,
* S_Suspend_Ind, S_Resume_Ind,
* S_MethodInvoke_Ind, S_MethodResult_Cnf, S_MethodAbort_Ind
* S_Unit_MethodInvoke_Ind (from wsp_unit)
*
* For most of these events the application layer is expected to send
* a response back to the session layer.
*/
#endif
gateway-1.4.3/wap/wtp_resp_machine.def 0000644 0001750 0001750 00000013351 11132672001 017010 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_resp_machine.def - macro call for generating WTP responder statemachine.
* See the architecture document for guidance how to use and update it.
*
* By Aarno Syvnen for Wapit Ltd.
*
* WTPRespMachine data structure includes current state of WTP responder state
* machine for a specific transaction. This means all data needed to handle at
* least two incoming events of a certain transaction. Its fields can be
* grouped following way:
*
* General: wtp responder machine state
*
* Fields telling the service required:
* a) transaction class (is transaction confirmed or not)
* b) user acknowledgement flag (do we wait for response primit-
* ive of WTP user (for instance, WSP) or not)
*
* Machine identification: address four-tuple and transaction identifier
*
* Field required for tid verification:
* a) packed wsp invoke indication, which is required by the
* protocol
*
* Fields required for reliable transmission:
* a) pointer to the timer of this machine in the timers list
* b) counters for acknowledgement waiting periods and retrans-
* missions
* c) flag telling are we resending the result or not
* d) similar flag for acknowledgements
* e) packed result message, for greater effectivity
*/
#if !defined(MACHINE)
#error "Macro MACHINE is missing."
#elif !defined(INTEGER)
#error "Macro INTEGER is missing."
#elif !defined(ENUM)
#error "Macro ENUM is missing."
#elif !defined(TIMER)
#error "Macro TIMER is missing."
#elif !defined(EVENT)
#error "Macro EVENT is missing."
#elif !defined(LIST)
#error "Macro LIST is missing."
#elif !defined(SARDATA)
#error "Macro SARDATA is missing."
#elif !defined(ADDRTUPLE)
#error "Macro ADDRTUPLE is missing."
#endif
MACHINE(ENUM(state)
INTEGER(tid) /* transaction identifier */
ADDRTUPLE(addr_tuple)
INTEGER(tcl) /* transaction class */
INTEGER(aec) /* counter telling how many timer periods
we have waited for acknowledgement */
INTEGER(rcr) /* retransmission counter */
INTEGER(u_ack) /* user acknowledgement flag (are user
acknowledgement required) */
INTEGER(rid) /* retransmission flag, telling are we
resending the result */
EVENT(result) /* packed result message - for resending */
INTEGER(ack_pdu_sent) /* are we resending the acknowledgement */
TIMER(timer) /* pointer to the timer of this machine timer
in the global timers list */
EVENT(invoke_indication) /* packed wsp invoke indication - for tid
verification */
EVENT(sar_invoke) /* initial invoke for SAR, accumulate user_data */
LIST(sar_info)
SARDATA(sar) /* ! NULL if were we asked for SAR */
)
#undef MACHINE
#undef INTEGER
#undef ENUM
#undef TIMER
#undef EVENT
#undef LIST
#undef SARDATA
#undef ADDRTUPLE
gateway-1.4.3/wap/wtp_resp.c 0000644 0001750 0001750 00000072331 11132672002 015014 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_resp.c - WTP responder implementation
*
* Aarno Syvnen
* Lars Wirzenius
*/
#include "gwlib/gwlib.h"
#include "wtp_resp.h"
#include "wtp_pack.h"
#include "wtp_tid.h"
#include "wtp.h"
#include "timers.h"
#include "wap.h"
/***********************************************************************
* Internal data structures.
*
* List of responder WTP machines.
*/
static List *resp_machines = NULL;
/*
* Counter for responder WTP machine id numbers, to make sure they are unique.
*/
static Counter *resp_machine_id_counter = NULL;
/*
* Give the status of wtp responder:
*
* limbo
* not running at all
* running
* operating normally
* terminating
* waiting for operations to terminate, returning to limbo
*/
static enum { limbo, running, terminating } resp_run_status = limbo;
wap_dispatch_func_t *dispatch_to_wdp;
wap_dispatch_func_t *dispatch_to_wsp;
wap_dispatch_func_t *dispatch_to_push;
/*
* Queue of events to be handled by WTP responder.
*/
static List *resp_queue = NULL;
/*
* Timer 'tick'. All wtp responder timer values are multiplies of this one
*/
static long resp_timer_freq = -1;
/*****************************************************************************
*
* Prototypes of internal functions:
*
* Create and destroy an uniniatilized wtp responder state machine.
*/
static WTPRespMachine *resp_machine_create(WAPAddrTuple *tuple, long tid,
long tcl);
static void resp_machine_destroy(void *sm);
/*
* Checks whether wtp responser machines data structure includes a specific
* machine.
* The machine in question is identified with with source and destination
* address and port and tid. If the machine does not exist and the event is
* RcvInvoke, a new machine is created and added in the machines data
* structure.
* First test incoming events (WTP 10.2) (Exception is tests nro 4 and 5: if
* we have a memory error, we panic. Nro 4 is already checked) If event was
* validated and If the event was RcvAck or RcvAbort, the event is ignored.
* If the event is RcvErrorPDU, new machine is created.
*/
static WTPRespMachine *resp_machine_find_or_create(WAPEvent *event);
/*
* Feed an event to a WTP responder state machine. Handle all errors by
* itself, do not report them to the caller. WSP indication or confirmation
* is handled by an included state table.
*/
static void resp_event_handle(WTPRespMachine *machine, WAPEvent *event);
/*
* Print a wtp responder machine state as a string.
*/
static char *name_resp_state(int name);
/*
* Find the wtp responder machine from the global list of wtp responder
* structures that corresponds to the five-tuple of source and destination
* addresses and ports and the transaction identifier. Return a pointer to
* the machine, or NULL if not found.
*/
static WTPRespMachine *resp_machine_find(WAPAddrTuple *tuple, long tid,
long mid);
static void main_thread(void *);
/*
* Start acknowledgement interval timer
*/
static void start_timer_A(WTPRespMachine *machine);
/*
* Start retry interval timer
*/
static void start_timer_R(WTPRespMachine *machine);
/*
* Start timeout interval timer.
*/
static void start_timer_W(WTPRespMachine *machine);
static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data);
static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason);
static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm);
static int erroneous_field_in(WAPEvent *event);
static void handle_wrong_version(WAPEvent *event);
/*
* SAR related functions.
*/
static WAPEvent *assembly_sar_event (WTPRespMachine *machine, int last_psn);
static int add_sar_transaction (WTPRespMachine *machine, Octstr *data, int psn);
/* static int is_wanted_sar_data (void *a, void *b); */
static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event);
static void begin_sar_result(WTPRespMachine *machine, WAPEvent *event);
static void continue_sar_result(WTPRespMachine *machine, WAPEvent *event);
static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event);
static void sar_info_destroy(void *sar_info);
static void sardata_destroy(void *sardata);
/*
* Create a datagram with an Abort PDU and send it to the WDP layer.
*/
static void send_abort(WTPRespMachine *machine, long type, long reason);
/*
* Create a datagram with an Ack PDU and send it to the WDP layer.
*/
static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag);
/******************************************************************************
*
* EXTERNAL FUNCTIONS:
*
*/
void wtp_resp_init(wap_dispatch_func_t *datagram_dispatch,
wap_dispatch_func_t *session_dispatch,
wap_dispatch_func_t *push_dispatch,
long timer_freq)
{
resp_machines = gwlist_create();
resp_machine_id_counter = counter_create();
resp_queue = gwlist_create();
gwlist_add_producer(resp_queue);
dispatch_to_wdp = datagram_dispatch;
dispatch_to_wsp = session_dispatch;
dispatch_to_push = push_dispatch;
timers_init();
resp_timer_freq = timer_freq;
wtp_tid_cache_init();
gw_assert(resp_run_status == limbo);
resp_run_status = running;
gwthread_create(main_thread, NULL);
}
void wtp_resp_shutdown(void)
{
gw_assert(resp_run_status == running);
resp_run_status = terminating;
gwlist_remove_producer(resp_queue);
gwthread_join_every(main_thread);
debug("wap.wtp", 0, "wtp_resp_shutdown: %ld resp_machines left",
gwlist_len(resp_machines));
gwlist_destroy(resp_machines, resp_machine_destroy);
gwlist_destroy(resp_queue, wap_event_destroy_item);
counter_destroy(resp_machine_id_counter);
wtp_tid_cache_shutdown();
timers_shutdown();
}
void wtp_resp_dispatch_event(WAPEvent *event)
{
gwlist_produce(resp_queue, event);
}
/*****************************************************************************
*
* INTERNAL FUNCTIONS:
*
*/
static void main_thread(void *arg)
{
WTPRespMachine *sm;
WAPEvent *e;
while (resp_run_status == running &&
(e = gwlist_consume(resp_queue)) != NULL) {
sm = resp_machine_find_or_create(e);
if (sm == NULL) {
wap_event_destroy(e);
} else {
resp_event_handle(sm, e);
}
}
}
/*
* Give the name of a responder state in a readable form.
*/
static char *name_resp_state(int s)
{
switch (s) {
#define STATE_NAME(state) case state: return #state;
#define ROW(state, event, condition, action, new_state)
#include "wtp_resp_states.def"
default:
return "unknown state";
}
}
/*
* Feed an event to a WTP responder state machine. Handle all errors yourself,
* do not report them to the caller. Note: Do not put {}s of the else block
* inside the macro definition.
*/
static void resp_event_handle(WTPRespMachine *resp_machine, WAPEvent *event)
{
WAPEvent *wsp_event = NULL;
/*
* We don't feed sar packets into state machine
* until we got the whole message
*/
if (process_sar_transaction(resp_machine,&event) == 0) {
debug("wap.wtp", 0, "SAR event received, wait for continue");
/* For removing state machine in case of incomplete sar */
start_timer_W(resp_machine);
if (event != NULL) {
wap_event_destroy(event);
}
return;
}
debug("wap.wtp", 0, "WTP: resp_machine %ld, state %s, event %s.",
resp_machine->mid,
name_resp_state(resp_machine->state),
wap_event_name(event->type));
#define STATE_NAME(state)
#define ROW(wtp_state, event_type, condition, action, next_state) \
if (resp_machine->state == wtp_state && \
event->type == event_type && \
(condition)) { \
action \
resp_machine->state = next_state; \
debug("wap.wtp", 0, "WTP %ld: New state %s", resp_machine->mid, #next_state); \
} else
#include "wtp_resp_states.def"
{
error(0, "WTP: handle_event: unhandled event!");
debug("wap.wtp", 0, "WTP: handle_event: Unhandled event was:");
wap_event_dump(event);
wap_event_destroy(event);
return;
}
if (event != NULL) {
wap_event_destroy(event);
}
if (resp_machine->state == LISTEN)
resp_machine_destroy(resp_machine);
}
static void handle_wrong_version(WAPEvent *event)
{
WAPEvent *ab;
if (event->type == RcvInvoke) {
ab = wtp_pack_abort(PROVIDER, WTPVERSIONZERO, event->u.RcvInvoke.tid,
event->u.RcvInvoke.addr_tuple);
dispatch_to_wdp(ab);
}
}
/*
* Check for features 7 and 9 in WTP 10.2.
*/
static int erroneous_field_in(WAPEvent *event)
{
return event->type == RcvInvoke && event->u.RcvInvoke.version != 0;
}
/*
* React features 7 and 9 in WTP 10.2, by aborting with an appropiate error
* message.
*/
static void handle_erroneous_field_in(WAPEvent *event)
{
if (event->type == RcvInvoke) {
if (event->u.RcvInvoke.version != 0) {
debug("wap.wtp_resp", 0, "WTP_RESP: wrong version, aborting"
"transaction");
handle_wrong_version(event);
}
}
}
/*
* Checks whether wtp machines data structure includes a specific machine.
* The machine in question is identified with with source and destination
* address and port and tid. First test incoming events (WTP 10.2)
* (Exception is tests nro 4 and 5: if we have a memory error, we panic. Nro 5
* is already checked) If event was validated and if the machine does not
* exist and the event is RcvInvoke, a new machine is created and added in
* the machines data structure. If the event was RcvAck or RcvAbort, the
* event is ignored (test nro 3). If the event is RcvErrorPDU (test nro 4)
* new machine is created for handling this event. If the event is one of WSP
* primitives, we have an error.
*/
static WTPRespMachine *resp_machine_find_or_create(WAPEvent *event)
{
WTPRespMachine *resp_machine = NULL;
long tid, mid;
WAPAddrTuple *tuple;
tid = -1;
tuple = NULL;
mid = -1;
switch (event->type) {
case RcvInvoke:
/* check if erroneous fields are given */
if (erroneous_field_in(event)) {
handle_erroneous_field_in(event);
return NULL;
} else {
tid = event->u.RcvInvoke.tid;
tuple = event->u.RcvInvoke.addr_tuple;
}
break;
case RcvSegInvoke:
tid = event->u.RcvSegInvoke.tid;
tuple = event->u.RcvSegInvoke.addr_tuple;
break;
case RcvAck:
tid = event->u.RcvAck.tid;
tuple = event->u.RcvAck.addr_tuple;
break;
case RcvNegativeAck:
tid = event->u.RcvAck.tid;
tuple = event->u.RcvAck.addr_tuple;
break;
case RcvAbort:
tid = event->u.RcvAbort.tid;
tuple = event->u.RcvAbort.addr_tuple;
break;
case RcvErrorPDU:
tid = event->u.RcvErrorPDU.tid;
tuple = event->u.RcvErrorPDU.addr_tuple;
break;
case TR_Invoke_Res:
mid = event->u.TR_Invoke_Res.handle;
break;
case TR_Result_Req:
mid = event->u.TR_Result_Req.handle;
break;
case TR_Abort_Req:
mid = event->u.TR_Abort_Req.handle;
break;
case TimerTO_A:
mid = event->u.TimerTO_A.handle;
break;
case TimerTO_R:
mid = event->u.TimerTO_R.handle;
break;
case TimerTO_W:
mid = event->u.TimerTO_W.handle;
break;
default:
debug("wap.wtp", 0, "WTP: resp_machine_find_or_create:"
"unhandled event");
wap_event_dump(event);
return NULL;
}
gw_assert(tuple != NULL || mid != -1);
resp_machine = resp_machine_find(tuple, tid, mid);
if (resp_machine == NULL){
switch (event->type) {
/*
* When PDU with an illegal header is received, its tcl-field is
* irrelevant and possibly meaningless). In this case we must create
* a new machine, if there is any. There is a machine for all events
* handled stateful manner.
*/
case RcvErrorPDU:
debug("wap.wtp_resp", 0, "an erronous pdu received");
wap_event_dump(event);
resp_machine = resp_machine_create(tuple, tid,
event->u.RcvInvoke.tcl);
break;
case RcvInvoke:
resp_machine = resp_machine_create(tuple, tid,
event->u.RcvInvoke.tcl);
/* if SAR requested */
if (!event->u.RcvInvoke.gtr || !event->u.RcvInvoke.ttr) {
resp_machine->sar = gw_malloc(sizeof(WTPSARData));
resp_machine->sar->nsegm = 0;
resp_machine->sar->csegm = 0;
resp_machine->sar->lsegm = 0;
resp_machine->sar->data = NULL;
}
break;
case RcvSegInvoke:
info(0, "WTP_RESP: resp_machine_find_or_create:"
" segmented invoke received, yet having no machine");
break;
/*
* This and the following branch implement test nro 3 in WTP 10.2.
*/
case RcvAck:
info(0, "WTP_RESP: resp_machine_find_or_create:"
" ack received, yet having no machine");
break;
case RcvNegativeAck:
info(0, "WTP_RESP: resp_machine_find_or_create:"
" negative ack received, yet having no machine");
break;
case RcvAbort:
info(0, "WTP_RESP: resp_machine_find_or_create:"
" abort received, yet having no machine");
break;
case TR_Invoke_Res:
case TR_Result_Req:
case TR_Abort_Req:
error(0, "WTP_RESP: resp_machine_find_or_create: WSP primitive to"
" a wrong WTP machine");
break;
case TimerTO_A:
case TimerTO_R:
case TimerTO_W:
error(0, "WTP_RESP: resp_machine_find_or_create: timer event"
" without a corresponding machine");
break;
default:
error(0, "WTP_RESP: resp_machine_find_or_create: unhandled event");
wap_event_dump(event);
break;
}
} /* if machine == NULL */
return resp_machine;
}
static int is_wanted_resp_machine(void *a, void *b)
{
machine_pattern *pat;
WTPRespMachine *m;
m = a;
pat = b;
if (m->mid == pat->mid)
return 1;
if (pat->mid != -1)
return 0;
return m->tid == pat->tid &&
wap_addr_tuple_same(m->addr_tuple, pat->tuple);
}
static WTPRespMachine *resp_machine_find(WAPAddrTuple *tuple, long tid,
long mid)
{
machine_pattern pat;
WTPRespMachine *m;
pat.tuple = tuple;
pat.tid = tid;
pat.mid = mid;
m = gwlist_search(resp_machines, &pat, is_wanted_resp_machine);
return m;
}
static WTPRespMachine *resp_machine_create(WAPAddrTuple *tuple, long tid,
long tcl)
{
WTPRespMachine *resp_machine;
resp_machine = gw_malloc(sizeof(WTPRespMachine));
#define ENUM(name) resp_machine->name = LISTEN;
#define EVENT(name) resp_machine->name = NULL;
#define INTEGER(name) resp_machine->name = 0;
#define TIMER(name) resp_machine->name = gwtimer_create(resp_queue);
#define ADDRTUPLE(name) resp_machine->name = NULL;
#define LIST(name) resp_machine->name = NULL;
#define SARDATA(name) resp_machine->name = NULL;
#define MACHINE(field) field
#include "wtp_resp_machine.def"
gwlist_append(resp_machines, resp_machine);
resp_machine->mid = counter_increase(resp_machine_id_counter);
resp_machine->addr_tuple = wap_addr_tuple_duplicate(tuple);
resp_machine->tid = tid;
resp_machine->tcl = tcl;
debug("wap.wtp", 0, "WTP: Created WTPRespMachine %p (%ld)",
(void *) resp_machine, resp_machine->mid);
return resp_machine;
}
/*
* Destroys a WTPRespMachine. Assumes it is safe to do so. Assumes it has
* already been deleted from the machines list.
*/
static void resp_machine_destroy(void * p)
{
WTPRespMachine *resp_machine;
resp_machine = p;
debug("wap.wtp", 0, "WTP: Destroying WTPRespMachine %p (%ld)",
(void *) resp_machine, resp_machine->mid);
gwlist_delete_equal(resp_machines, resp_machine);
#define ENUM(name) resp_machine->name = LISTEN;
#define EVENT(name) wap_event_destroy(resp_machine->name);
#define INTEGER(name) resp_machine->name = 0;
#define TIMER(name) gwtimer_destroy(resp_machine->name);
#define ADDRTUPLE(name) wap_addr_tuple_destroy(resp_machine->name);
#define LIST(name) gwlist_destroy(resp_machine->name,sar_info_destroy);
#define SARDATA(name) sardata_destroy(resp_machine->name);
#define MACHINE(field) field
#include "wtp_resp_machine.def"
gw_free(resp_machine);
}
/*
* Create a TR-Invoke.ind event.
*/
static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data)
{
WAPEvent *event;
event = wap_event_create(TR_Invoke_Ind);
event->u.TR_Invoke_Ind.ack_type = sm->u_ack;
event->u.TR_Invoke_Ind.user_data = octstr_duplicate(user_data);
event->u.TR_Invoke_Ind.tcl = sm->tcl;
event->u.TR_Invoke_Ind.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
event->u.TR_Invoke_Ind.handle = sm->mid;
return event;
}
/*
* Create a TR-Result.cnf event.
*/
static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm)
{
WAPEvent *event;
event = wap_event_create(TR_Result_Cnf);
event->u.TR_Result_Cnf.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
event->u.TR_Result_Cnf.handle = sm->mid;
return event;
}
/*
* Creates TR-Abort.ind event from a responder state machine. In addition, set
* the responder indication flag.
*/
static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason) {
WAPEvent *event;
event = wap_event_create(TR_Abort_Ind);
event->u.TR_Abort_Ind.abort_code = abort_reason;
event->u.TR_Abort_Ind.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
event->u.TR_Abort_Ind.handle = sm->mid;
event->u.TR_Abort_Ind.ir_flag = RESPONDER_INDICATION;
return event;
}
/*
* Start acknowledgement interval timer. Multiply time with
* resp_timer_freq.
*/
static void start_timer_A(WTPRespMachine *machine)
{
WAPEvent *timer_event;
timer_event = wap_event_create(TimerTO_A);
timer_event->u.TimerTO_A.handle = machine->mid;
gwtimer_start(machine->timer, L_A_WITH_USER_ACK * resp_timer_freq,
timer_event);
}
/*
* Start retry interval timer. Multiply time with resp_timer_freq.
*/
static void start_timer_R(WTPRespMachine *machine)
{
WAPEvent *timer_event;
timer_event = wap_event_create(TimerTO_R);
timer_event->u.TimerTO_R.handle = machine->mid;
gwtimer_start(machine->timer, L_R_WITH_USER_ACK * resp_timer_freq,
timer_event);
}
/*
* Start segmentation timeout interval timer. Multiply time with
* resp_timer_freq.
*/
static void start_timer_W(WTPRespMachine *machine)
{
WAPEvent *timer_event;
timer_event = wap_event_create(TimerTO_W);
timer_event->u.TimerTO_W.handle = machine->mid;
gwtimer_start(machine->timer, W_WITH_USER_ACK * resp_timer_freq,
timer_event);
}
static void send_abort(WTPRespMachine *machine, long type, long reason)
{
WAPEvent *e;
e = wtp_pack_abort(type, reason, machine->tid, machine->addr_tuple);
dispatch_to_wdp(e);
}
static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag)
{
WAPEvent *e;
e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple);
dispatch_to_wdp(e);
}
/*
* Process incoming event, checking for WTP SAR
*/
static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event)
{
WAPEvent *e, *orig_event;
int psn;
orig_event = *event;
if (orig_event->type == RcvInvoke) {
if (!orig_event->u.RcvInvoke.ttr || !orig_event->u.RcvInvoke.gtr) { /* SAR */
/* Ericcson set TTR flag even if we have the only part */
if (orig_event->u.RcvInvoke.ttr == 1) {
return 1; /* Not SAR although TTR flag was set */
} else {
/* save initial event */
machine->sar_invoke = wap_event_duplicate(orig_event);
/* save data into list with psn = 0 */
add_sar_transaction(machine, orig_event->u.RcvInvoke.user_data, 0);
if (orig_event->u.RcvInvoke.gtr == 1) { /* Need to acknowledge */
e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid,
machine->addr_tuple, 0);
dispatch_to_wdp(e);
}
return 0;
}
} else {
return 1; /* Not SAR */
}
}
if (orig_event->type == RcvSegInvoke) {
add_sar_transaction(machine, orig_event->u.RcvSegInvoke.user_data,
orig_event->u.RcvSegInvoke.psn);
if (orig_event->u.RcvSegInvoke.gtr == 1) { /* Need to acknowledge */
e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid, machine->addr_tuple,
orig_event->u.RcvSegInvoke.psn);
dispatch_to_wdp(e);
}
if (orig_event->u.RcvSegInvoke.ttr == 1) { /* Need to feed to WSP */
/* Create assembled event */
psn = orig_event->u.RcvSegInvoke.psn;
wap_event_destroy(orig_event);
*event = assembly_sar_event(machine,psn);
gw_assert(event != NULL);
return 1;
}
return 0;
}
/* Not SAR message */
return 1;
}
static int is_wanted_sar_data(void *a, void *b)
{
sar_info_t *s;
int *i;
s = a;
i = b;
if (*i == s->sar_psn) {
return 1;
} else {
return 0;
}
}
/*
* Return 0 if transaction added suscessufully, 1 otherwise.
*/
static int add_sar_transaction(WTPRespMachine *machine, Octstr *data, int psn)
{
sar_info_t *sar_info;
if (machine->sar_info == NULL) {
machine->sar_info = gwlist_create();
}
if (gwlist_search(machine->sar_info, &psn, is_wanted_sar_data) == NULL) {
sar_info = gw_malloc(sizeof(sar_info_t));
sar_info->sar_psn = psn;
sar_info->sar_data = octstr_duplicate(data);
gwlist_append(machine->sar_info, sar_info);
return 0;
} else {
debug("wap.wtp", 0, "Duplicated psn found, ignore packet");
return 1;
}
}
static WAPEvent *assembly_sar_event(WTPRespMachine *machine, int last_psn)
{
WAPEvent *e;
int i;
sar_info_t *sar_info;
e = wap_event_duplicate(machine->sar_invoke);
for (i = 1; i <= last_psn; i++) {
if ((sar_info = gwlist_search(machine->sar_info, &i, is_wanted_sar_data)) != NULL) {
octstr_append(e->u.RcvInvoke.user_data,sar_info->sar_data);
} else {
debug("wap.wtp", 0, "Packet with psn %d not found", i);
return e;
}
}
return e;
}
static void sar_info_destroy(void *p)
{
sar_info_t *sar_info;
sar_info = p;
octstr_destroy(sar_info->sar_data);
gw_free(sar_info);
}
static void sardata_destroy(void *p)
{
WTPSARData * sardata;
if (p) {
sardata = p;
octstr_destroy(sardata->data);
gw_free(sardata);
}
}
static void begin_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
{
WAPEvent *result;
WTPSARData *sar;
int psn;
gw_assert(resp_machine->sar != NULL);
sar = resp_machine->sar;
sar->data = octstr_duplicate(event->u.TR_Result_Req.user_data);
sar->nsegm = (octstr_len(sar->data)-1)/SAR_SEGM_SIZE;
sar->tr = sar->lsegm = 0;
sar->csegm = -1;
debug("wap.wtp", 0, "WTP: begin_sar_result(): data len = %lu",
octstr_len(sar->data));
for (psn = 0; !sar->tr; psn++) {
result = wtp_pack_sar_result(resp_machine, psn);
if (sar->tr)
resp_machine->result = wap_event_duplicate(result);
debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
dispatch_to_wdp(result);
sar->lsegm = psn;
}
resp_machine->rid = 1;
}
static void continue_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
{
WAPEvent *result;
WTPSARData *sar;
int psn;
gw_assert(resp_machine->sar != NULL && event->type == RcvAck);
sar = resp_machine->sar;
debug("wap.wtp", 0, "WTP: continue_sar_result(): lsegm=%d, nsegm=%d, csegm=%d",
sar->lsegm, sar->nsegm, sar->csegm);
start_timer_R(resp_machine);
if (event->u.RcvAck.psn>sar->csegm) {
sar->csegm = event->u.RcvAck.psn;
}
sar->tr = 0;
wap_event_destroy(resp_machine->result);
resp_machine->result = NULL;
for (psn = sar->csegm + 1; !sar->tr; psn++) {
result = wtp_pack_sar_result(resp_machine, psn);
if (sar->tr)
resp_machine->result = wap_event_duplicate(result);
debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u",psn);
dispatch_to_wdp(result);
sar->lsegm = psn;
}
}
static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
{
WAPEvent *result;
WTPSARData *sar;
int psn, i;
gw_assert(resp_machine->sar != NULL && event->type == RcvNegativeAck);
sar = resp_machine->sar;
debug("wap.wtp", 0, "WTP: resend_sar_result(): lsegm=%d, nsegm=%d, csegm=%d",
sar->lsegm, sar->nsegm, sar->csegm);
start_timer_R(resp_machine);
if (event->u.RcvNegativeAck.nmissing) {
/* if we have a list of missed packets */
for(i = 0; i < event->u.RcvNegativeAck.nmissing; i++) {
if ((psn = octstr_get_char(event->u.RcvNegativeAck.missing, i)) >= 0) {
result = wtp_pack_sar_result(resp_machine, psn);
wtp_pack_set_rid(result, 1);
debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
dispatch_to_wdp(result);
}
}
} else {
/* if we have to resend a whole group */
sar->tr = 0;
for (psn = sar->csegm+1; !sar->tr; psn++) {
result = wtp_pack_sar_result(resp_machine, psn);
wtp_pack_set_rid(result, 1);
debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
dispatch_to_wdp(result);
}
}
}
gateway-1.4.3/wap/wtp_pdu.c 0000644 0001750 0001750 00000031244 11132672002 014631 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wtp_pdu.c - pack and unpack WTP packets
*
* Generates packing and unpacking code from wtp_pdu.def.
*
* Richard Braakman
*/
#include "gwlib/gwlib.h"
#include "wtp_pdu.h"
WTP_PDU *wtp_pdu_create(int type) {
WTP_PDU *pdu;
pdu = gw_malloc(sizeof(*pdu));
pdu->type = type;
pdu->options = NULL;
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: {\
struct name *p; p = &pdu->u.name; \
fields \
} break;
#define UINT(field, docstring, bits) p->field = 0;
#define UINTVAR(field, docstring) p->field = 0;
#define OCTSTR(field, docstring, lengthfield) p->field = NULL;
#define REST(field, docstring) p->field = NULL;
#define TYPE(bits, value)
#define RESERVED(bits)
#define TPI(confield)
#include "wtp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
warning(0, "Cannot create unknown WTP PDU type %d", pdu->type);
break;
}
return pdu;
}
void wtp_pdu_destroy(WTP_PDU *pdu) {
if (pdu == NULL)
return;
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: {\
struct name *p; p = &pdu->u.name; \
fields \
} break;
#define UINT(field, docstring, bits)
#define UINTVAR(field, docstring)
#define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field);
#define REST(field, docstring) octstr_destroy(p->field);
#define TYPE(bits, value)
#define RESERVED(bits)
#define TPI(confield)
#include "wtp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type);
break;
}
if (pdu->options) {
while (gwlist_len(pdu->options)) {
wtp_tpi_destroy(gwlist_consume(pdu->options));
}
gwlist_destroy(pdu->options, NULL);
}
gw_free(pdu);
}
void wtp_tpi_destroy(WTP_TPI *p) {
if (p == NULL)
return;
octstr_destroy(p->data);
gw_free(p);
}
void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data) {
WTP_TPI *tpi;
tpi = gw_malloc(sizeof(*tpi));
tpi->type = type;
tpi->data = data;
if (pdu->options == NULL)
pdu->options = gwlist_create();
gwlist_append(pdu->options, tpi);
}
static long unpack_tpis(Octstr *data, long bitpos, WTP_PDU *pdu) {
long length;
int type;
Octstr *tpidata;
int another;
do {
another = octstr_get_bits(data, bitpos, 1);
type = octstr_get_bits(data, bitpos + 1, 4);
if (octstr_get_bits(data, bitpos + 5, 1)) {
/* Long TPI */
length = octstr_get_bits(data, bitpos + 8, 8);
bitpos += 16;
} else {
/* Short TPI */
length = octstr_get_bits(data, bitpos + 6, 2);
bitpos += 8;
}
gw_assert(bitpos % 8 == 0);
tpidata = octstr_copy(data, bitpos / 8, length);
bitpos += 8 * length;
wtp_pdu_append_tpi(pdu, type, tpidata);
} while (another);
return bitpos;
}
static long pack_tpis(Octstr *data, long bitpos, List *tpis) {
long length;
WTP_TPI *tpi;
int i;
int num_tpis;
num_tpis = gwlist_len(tpis);
for (i = 0; i < num_tpis; i++) {
tpi = gwlist_get(tpis, i);
length = octstr_len(tpi->data);
octstr_set_bits(data, bitpos, 1, i + 1 < num_tpis);
octstr_set_bits(data, bitpos + 1, 4, tpi->type);
if (length >= 4) {
/* Long TPI */
octstr_set_bits(data, bitpos + 5, 1, 1);
octstr_set_bits(data, bitpos + 8, 8, length);
bitpos += 16;
} else {
/* Short TPI */
octstr_set_bits(data, bitpos + 5, 1, 0);
octstr_set_bits(data, bitpos + 6, 2, length);
bitpos += 8;
}
gw_assert(bitpos % 8 == 0);
octstr_append(data, tpi->data);
bitpos += 8 * length;
}
return bitpos;
}
static void dump_tpis(List *tpis, int level) {
int i;
int num_tpis;
WTP_TPI *tpi;
if (tpis == NULL)
return;
num_tpis = gwlist_len(tpis);
for (i = 0; i < num_tpis; i++) {
tpi = gwlist_get(tpis, i);
debug("wap.wtp", 0, "%*s TPI type %u:", level, "", tpi->type);
octstr_dump(tpi->data, level + 1);
}
}
/* Determine which type of PDU this is, using the TYPE macros in
* the definition file. */
static int wtp_pdu_type(Octstr *data) {
long bitpos;
long lastpos = -1;
long lastnumbits = -1;
long lastval = -1;
int thistype;
/* This code looks slow, but an optimizing compiler will
* reduce it considerably. gcc -O2 will produce a single
* call to octstr_get_bits, folllowed by a sequence of
* tests on lastval. */
/* Only UINT and RESERVED fields may precede the TYPE */
#define PDU(name, docstring, fields, is_valid) \
bitpos = 0; \
thistype = name; \
fields
#define UINT(field, docstring, bits) bitpos += (bits);
#define UINTVAR(field, docstring)
#define OCTSTR(field, docstring, lengthfield)
#define REST(field, docstring)
#define TYPE(bits, value) \
if ((bits) != lastnumbits || bitpos != lastpos) { \
lastval = octstr_get_bits(data, bitpos, (bits)); \
} \
if (lastval == (value)) \
return thistype; \
lastnumbits = (bits); \
lastpos = bitpos;
#define RESERVED(bits) bitpos += (bits);
#define TPI(confield)
#include "wtp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
return -1;
}
WTP_PDU *wtp_pdu_unpack(Octstr *data) {
WTP_PDU *pdu = NULL;
long bitpos = 0;
gw_assert(data != NULL);
pdu = gw_malloc(sizeof(*pdu));
pdu->type = wtp_pdu_type(data);
pdu->options = NULL;
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: { \
struct name *p = &pdu->u.name; \
fields \
gw_assert(bitpos % 8 == 0); \
if (bitpos / 8 != octstr_len(data)) { \
warning(0, "Bad length for " #name " PDU, " \
"expected %ld", bitpos / 8); \
} \
if (!(is_valid)) { \
warning(0, #name " PDU failed %s", #is_valid); \
return NULL; \
} \
} break;
#define UINT(field, docstring, bits) \
p->field = octstr_get_bits(data, bitpos, (bits)); \
bitpos += (bits);
#define UINTVAR(field, docstring) \
gw_assert(bitpos % 8 == 0); \
p->field = octstr_get_bits(data, bitpos + 1, 7); \
while (octstr_get_bits(data, bitpos, 1)) { \
bitpos += 8; \
p->field <<= 7; \
p->field |= octstr_get_bits(data, bitpos + 1, 7); \
} \
bitpos += 8;
#define OCTSTR(field, docstring, lengthfield) \
gw_assert(bitpos % 8 == 0); \
p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \
bitpos += 8 * p->lengthfield;
#define REST(field, docstring) \
gw_assert(bitpos % 8 == 0); \
if (bitpos / 8 <= octstr_len(data)) { \
p->field = octstr_copy(data, bitpos / 8, \
octstr_len(data) - bitpos / 8); \
bitpos = octstr_len(data) * 8; \
} else { \
p->field = octstr_create(""); \
}
#define TYPE(bits, value) bitpos += (bits);
#define RESERVED(bits) bitpos += (bits);
#define TPI(confield) \
if (p->confield) { \
pdu->options = gwlist_create(); \
bitpos = unpack_tpis(data, bitpos, pdu); \
}
#include "wtp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
warning(0, "WTP PDU with unknown type %d", pdu->type);
gw_free(pdu);
return NULL;
}
return pdu;
}
static void fixup_length_fields(WTP_PDU *pdu) {
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: { \
struct name *p = &pdu->u.name; \
fields \
} break;
#define UINT(field, docstring, bits)
#define UINTVAR(field, docstring)
#define OCTSTR(field, docstring, lengthfield) \
p->lengthfield = octstr_len(p->field);
#define REST(field, docstring)
#define TYPE(bits, value)
#define RESERVED(bits)
#define TPI(confield) \
p->confield = pdu->options != NULL && gwlist_len(pdu->options) > 0;
#include "wtp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
}
}
Octstr *wtp_pdu_pack(WTP_PDU *pdu) {
Octstr *data;
long bitpos;
/* We rely on octstr_set_bits to lengthen our octstr as needed. */
data = octstr_create("");
fixup_length_fields(pdu);
bitpos = 0;
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: { \
struct name *p = &pdu->u.name; \
fields \
gw_assert(bitpos % 8 == 0); \
} break;
#define UINT(field, docstring, bits) \
octstr_set_bits(data, bitpos, (bits), p->field); \
bitpos += (bits);
#define UINTVAR(field, docstring) \
gw_assert(bitpos % 8 == 0); \
octstr_append_uintvar(data, p->field); \
bitpos = 8 * octstr_len(data);
#define OCTSTR(field, docstring, lengthfield) \
gw_assert(bitpos % 8 == 0); \
if (p->field != NULL) \
octstr_append(data, p->field); \
bitpos += 8 * octstr_len(p->field);
#define REST(field, docstring) \
gw_assert(bitpos % 8 == 0); \
if (p->field != NULL) \
octstr_append(data, p->field); \
bitpos += 8 * octstr_len(p->field);
#define TYPE(bits, value) \
octstr_set_bits(data, bitpos, (bits), (value)); \
bitpos += (bits);
#define RESERVED(bits) bitpos += (bits);
#define TPI(confield) \
if (p->confield) { \
bitpos = pack_tpis(data, bitpos, pdu->options); \
}
#include "wtp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
panic(0, "Packing unknown WTP PDU type %ld", (long) pdu->type);
}
return data;
}
void wtp_pdu_dump(WTP_PDU *pdu, int level) {
char *dbg = "wap.wtp";
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: { \
struct name *p = &pdu->u.name; \
debug(dbg, 0, "%*sWTP %s PDU at %p:", \
level, "", #name, (void *)pdu); \
fields \
} break;
#define UINT(field, docstring, bits) \
debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
#define UINTVAR(field, docstring) \
debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
#define OCTSTR(field, docstring, lengthfield) \
debug(dbg, 0, "%*s %s:", level, "", docstring); \
octstr_dump(p->field, level + 1);
#define REST(field, docstring) \
debug(dbg, 0, "%*s %s:", level, "", docstring); \
octstr_dump(p->field, level + 1);
#define TYPE(bits, value)
#define RESERVED(bits)
#define TPI(confield) dump_tpis(pdu->options, level);
#include "wtp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
debug(dbg, 0, "%*sWTP PDU at %p:", level, "", (void *)pdu);
debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
break;
}
}
gateway-1.4.3/wap/wtp_tid.h 0000644 0001750 0001750 00000007630 11132672001 014627 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_tid.h - tid verification implementation header
*
* By Aarno Syvnen for WapIT Ltd
*/
#ifndef WTP_TID_H
#define WTP_TID_H
typedef struct WTPCached_tid WTPCached_tid;
#include
#include
#include "gwlib/gwlib.h"
#include "wap_events.h"
#include "wtp_resp.h"
#define WTP_TID_WINDOW_SIZE (1L << 14)
/*
* Constants defining the result of tid validation
*/
enum {
no_cached_tid,
ok,
fail
};
/*
* Tid cache item consists of initiator identifier and cached tid.
*/
struct WTPCached_tid {
WAPAddrTuple *addr_tuple;
long tid;
};
/*
* Initialize tid cache. MUST be called before calling other functions in this
* module.
*/
void wtp_tid_cache_init(void);
/*
* Shut down the tid cache. MUST be called after tid cache isn't used anymore.
*/
void wtp_tid_cache_shutdown(void);
/*
* Does the tid validation test, by using a simple window mechanism
*
* Returns: no_cached_tid, if the peer has no cached last tid, or the result
* of the test (ok, fail);
*/
int wtp_tid_is_valid(WAPEvent *event, WTPRespMachine *machine);
/*
* Changes the tid value belonging to an existing initiator
*/
void wtp_tid_set_by_machine(WTPRespMachine *machine, long tid);
#endif
gateway-1.4.3/wap/wap_addr.h 0000644 0001750 0001750 00000006673 11132672003 014746 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wap_addr.h - interface to WAPAddr and WAPAddrTuple types.
*/
#ifndef WAP_ADDR_H
#define WAP_ADDR_H
#include "gwlib/gwlib.h"
typedef struct {
Octstr *address;
in_addr_t iaddr;
long port;
} WAPAddr;
typedef struct {
WAPAddr *remote, *local;
} WAPAddrTuple;
WAPAddr *wap_addr_create(Octstr *address, long port);
void wap_addr_destroy(WAPAddr *addr);
int wap_addr_same(WAPAddr *a, WAPAddr *b);
WAPAddrTuple *wap_addr_tuple_create(Octstr *rmt_addr, long rmt_port,
Octstr *lcl_addr, long lcl_port);
void wap_addr_tuple_destroy(WAPAddrTuple *tuple);
int wap_addr_tuple_same(WAPAddrTuple *a, WAPAddrTuple *b);
WAPAddrTuple *wap_addr_tuple_duplicate(WAPAddrTuple *tuple);
void wap_addr_tuple_dump(WAPAddrTuple *tuple);
#endif
gateway-1.4.3/wap/wtp_init.c 0000644 0001750 0001750 00000042374 11132672003 015013 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_init.c - WTP initiator implementation
*
* By Aarno Syvnen for Wapit Ltd
*/
#include "gwlib/gwlib.h"
#include "wtp_init.h"
#include "wtp_pack.h"
#include "wap.h"
/*****************************************************************************
* Internal data structures.
*
* List of initiator WTP machines
*/
static List *init_machines = NULL;
/*
* Counter for initiator WTP machine id numbers, to make sure they are unique.
*/
static Counter *init_machine_id_counter = NULL;
/*
* When we restart an iniator, we must set tidnew flag to avoid excessive tid
* validations (WTP 8.8.3.2). Only an iniator uses this flag.
*/
static int tidnew = 1;
/*
* Queue of events to be handled by WTP initiator.
*/
static List *queue = NULL;
/*
* Give the status of the wtp initiator:
*
* limbo
* not running at all
* running
* operating normally
* terminating
* waiting for operations to terminate, returning to limbo
*/
static enum { limbo, running, terminating } initiator_run_status = limbo;
static wap_dispatch_func_t *dispatch_to_wdp;
static wap_dispatch_func_t *dispatch_to_wsp;
/*
* This is a timer 'tick'. All timer values multiplies of this value.
*/
static long init_timer_freq = -1;
/***************************************************************************
*
* Prototypes for internal functions:
*/
static void main_thread(void *arg);
/*
* Create and destroy an uniniatilised wtp initiator state machine
*/
static WTPInitMachine *init_machine_create(WAPAddrTuple *tuple, unsigned short
tid, int tidnew);
static void init_machine_destroy(void *sm);
static void handle_init_event(WTPInitMachine *machine, WAPEvent *event);
/*
* Checks whether wtp initiator machines data structure includes a specific
* machine.
* The machine in question is identified with with source and destination
* address and port and tid.
*/
static WTPInitMachine *init_machine_find_or_create(WAPEvent *event);
/*
* Creates TR-Abort.ind event.
*/
static WAPEvent *create_tr_abort_ind(WTPInitMachine *sm, long abort_reason);
/*
* Creates TR-Invoke.cnf event
*/
static WAPEvent *create_tr_invoke_cnf(WTPInitMachine *machine);
static int tid_wrapped(unsigned short tid);
/*
* Create a datagram with an Abort PDU and send it to the WDP layer.
*/
static void send_abort(WTPInitMachine *machine, long type, long reason);
/*
* Create a datagram with an Ack PDU and send it to the WDP layer.
*/
static void send_ack(WTPInitMachine *machine, long ack_type, int rid_flag);
/*
* We use RcvTID consistently as a internal tid representation. So newly
* created tids are converted. SendTID = RcvTID ^ 0x8000 (WTP 10.4.3) and for
* an initiator, GenTID = SendTID (WTP 10.5).
*/
static unsigned short rcv_tid(unsigned short tid);
static void start_initiator_timer_R(WTPInitMachine *machine);
static void stop_initiator_timer(Timer *timer);
/**************************************************************************
*
* EXTERNAL FUNCTIONS
*/
void wtp_initiator_init(wap_dispatch_func_t *datagram_dispatch,
wap_dispatch_func_t *session_dispatch, long timer_freq)
{
init_machines = gwlist_create();
init_machine_id_counter = counter_create();
queue = gwlist_create();
gwlist_add_producer(queue);
dispatch_to_wdp = datagram_dispatch;
dispatch_to_wsp = session_dispatch;
timers_init();
init_timer_freq = timer_freq;
gw_assert(initiator_run_status == limbo);
initiator_run_status = running;
gwthread_create(main_thread, NULL);
}
void wtp_initiator_shutdown(void)
{
gw_assert(initiator_run_status == running);
initiator_run_status = terminating;
gwlist_remove_producer(queue);
gwthread_join_every(main_thread);
debug("wap.wtp", 0, "wtp_initiator_shutdown: %ld init_machines left",
gwlist_len(init_machines));
gwlist_destroy(init_machines, init_machine_destroy);
gwlist_destroy(queue, wap_event_destroy_item);
counter_destroy(init_machine_id_counter);
timers_shutdown();
}
void wtp_initiator_dispatch_event(WAPEvent *event)
{
gwlist_produce(queue, event);
}
/**************************************************************************
*
* INTERNAL FUNCTIONS:
*/
static void main_thread(void *arg)
{
WTPInitMachine *sm;
WAPEvent *e;
while (initiator_run_status == running &&
(e = gwlist_consume(queue)) != NULL) {
sm = init_machine_find_or_create(e);
if (sm == NULL)
wap_event_destroy(e);
else
handle_init_event(sm, e);
}
}
static WTPInitMachine *init_machine_create(WAPAddrTuple *tuple, unsigned short
tid, int tidnew)
{
WTPInitMachine *init_machine;
init_machine = gw_malloc(sizeof(WTPInitMachine));
#define ENUM(name) init_machine->name = INITIATOR_NULL_STATE;
#define INTEGER(name) init_machine->name = 0;
#define EVENT(name) init_machine->name = NULL;
#define TIMER(name) init_machine->name = gwtimer_create(queue);
#define ADDRTUPLE(name) init_machine->name = NULL;
#define MACHINE(field) field
#include "wtp_init_machine.def"
gwlist_append(init_machines, init_machine);
init_machine->mid = counter_increase(init_machine_id_counter);
init_machine->addr_tuple = wap_addr_tuple_duplicate(tuple);
init_machine->tid = tid;
init_machine->tidnew = tidnew;
debug("wap.wtp", 0, "WTP: Created WTPInitMachine %p (%ld)",
(void *) init_machine, init_machine->mid);
return init_machine;
}
/*
* Destroys a WTPInitMachine. Assumes it is safe to do so. Assumes it has
* already been deleted from the machines list.
*/
static void init_machine_destroy(void *p)
{
WTPInitMachine *init_machine;
init_machine = p;
debug("wap.wtp", 0, "WTP: Destroying WTPInitMachine %p (%ld)",
(void *) init_machine, init_machine->mid);
gwlist_delete_equal(init_machines, init_machine);
#define ENUM(name) init_machine->name = INITIATOR_NULL_STATE;
#define INTEGER(name) init_machine->name = 0;
#define EVENT(name) wap_event_destroy(init_machine->name);
#define TIMER(name) gwtimer_destroy(init_machine->name);
#define ADDRTUPLE(name) wap_addr_tuple_destroy(init_machine->name);
#define MACHINE(field) field
#include "wtp_init_machine.def"
gw_free(init_machine);
}
/*
* Give the name of an initiator state in a readable form.
*/
static unsigned char *name_init_state(int s)
{
switch (s){
#define INIT_STATE_NAME(state) case state: return (unsigned char *) #state;
#define ROW(state, event, condition, action, new_state)
#include "wtp_init_states.def"
default:
return (unsigned char *)"unknown state";
}
}
/*
* Feed an event to a WTP initiator state machine. Handle all errors by do not
* report them to the caller. WSP indication or conformation is handled by an
* included state table. Note: Do not put {}s of the else block inside the
* macro definition .
*/
static void handle_init_event(WTPInitMachine *init_machine, WAPEvent *event)
{
WAPEvent *wsp_event = NULL;
debug("wap.wtp", 0, "WTP_INIT: initiator machine %ld, state %s,"
" event %s.",
init_machine->mid,
name_init_state(init_machine->state),
wap_event_name(event->type));
#define INIT_STATE_NAME(state)
#define ROW(init_state, event_type, condition, action, next_state) \
if (init_machine->state == init_state && \
event->type == event_type && \
(condition)) { \
action \
init_machine->state = next_state; \
debug("wap.wtp", 0, "WTP_INIT %ld: New state %s", \
init_machine->mid, #next_state); \
} else
#include "wtp_init_states.def"
{
error(1, "WTP_INIT: handle_init_event: unhandled event!");
debug("wap.wtp.init", 0, "WTP_INIT: handle_init_event:"
"Unhandled event was:");
wap_event_dump(event);
wap_event_destroy(event);
return;
}
if (event != NULL) {
wap_event_destroy(event);
}
if (init_machine->state == INITIATOR_NULL_STATE)
init_machine_destroy(init_machine);
}
static int is_wanted_init_machine(void *a, void *b)
{
struct machine_pattern *pat;
WTPInitMachine *m;
m = a;
pat = b;
if (m->mid == pat->mid)
return 1;
if (pat->mid != -1)
return 0;
return m->tid == pat->tid &&
wap_addr_tuple_same(m->addr_tuple, pat->tuple);
}
static WTPInitMachine *init_machine_find(WAPAddrTuple *tuple, long tid,
long mid)
{
struct machine_pattern pat;
WTPInitMachine *m;
pat.tuple = tuple;
pat.tid = tid;
pat.mid = mid;
m = gwlist_search(init_machines, &pat, is_wanted_init_machine);
return m;
}
/*
* Checks whether wtp initiator machines data structure includes a specific
* machine. The machine in question is identified with with source and
* destination address and port and tid. First test incoming events
* (WTP 10.2) (Exception are tests nro 4 and 5: if we have a memory error,
* we panic (nro 4); nro 5 is already checked). If we have an ack with tid
* verification flag set and no corresponding transaction, we abort.(case nro
* 2). If the event was a normal ack or an abort, it is ignored (error nro 3).
* In the case of TR-Invoke.req a new machine is created, in the case of
* TR-Abort.req we have a serious error. We must create a new tid for a new
* transaction here, because machines are identified by an address tuple and a
* tid. This tid is GenTID (WTP 10.4.2), which is used only by the wtp iniator
* thread.
* Note that as internal tid representation, module uses RcvTID (as required
* by module wtp_pack). So we we turn the first bit of the tid stored by the
* init machine.
*/
static WTPInitMachine *init_machine_find_or_create(WAPEvent *event)
{
WTPInitMachine *machine = NULL;
long mid;
static long tid = -1;
WAPAddrTuple *tuple;
mid = -1;
tuple = NULL;
switch (event->type) {
case RcvAck:
tid = event->u.RcvAck.tid;
tuple = event->u.RcvAck.addr_tuple;
break;
case RcvAbort:
tid = event->u.RcvAbort.tid;
tuple = event->u.RcvAbort.addr_tuple;
break;
case RcvErrorPDU:
mid = event->u.RcvErrorPDU.tid;
tid = event->u.RcvErrorPDU.tid;
tuple = event->u.RcvErrorPDU.addr_tuple;
break;
/*
* When we are receiving an invoke requirement, we must create a new trans-
* action and generate a new tid. This can be wrapped, and should have its
* first bit turned.
*/
case TR_Invoke_Req:
++tid;
if (tid_wrapped(tid)) {
tidnew = 1;
tid = 0;
}
tid = rcv_tid(tid);
tuple = event->u.TR_Invoke_Req.addr_tuple;
mid = event->u.TR_Invoke_Req.handle;
break;
case TR_Abort_Req:
tid = event->u.TR_Abort_Req.handle;
break;
case TimerTO_R:
mid = event->u.TimerTO_R.handle;
break;
default:
error(0, "WTP_INIT: machine_find_or_create: unhandled event");
wap_event_dump(event);
return NULL;
}
gw_assert(tuple != NULL || mid != -1);
machine = init_machine_find(tuple, tid, mid);
if (machine == NULL){
switch (event->type){
case RcvAck:
/*
* Case nro 2 If we do not have a tid asked for, we send a negative answer,
* i.e. an abort with reason INVALIDTID.
*/
if (event->u.RcvAck.tid_ok) {
dispatch_to_wdp(wtp_pack_abort(PROVIDER, INVALIDTID,
tid, tuple));
}
/* Case nro 3, normal ack */
else
info(0, "WTP_INIT: machine_find_or_create: ack "
"received, yet having no machine");
break;
/* Case nro 3, abort */
case RcvAbort:
info(0, "WTP_INIT: machine_find_or_create: abort "
"received, yet having no machine");
break;
case TR_Invoke_Req:
machine = init_machine_create(tuple, tid, tidnew);
machine->mid = event->u.TR_Invoke_Req.handle;
break;
case TR_Abort_Req:
error(0, "WTP_INIT: machine_find_or_create: WSP "
"primitive to a wrong WTP machine");
break;
case TimerTO_R:
error(0, "WTP_INIT: machine_find_or_create: timer "
"event without a corresponding machine");
break;
default:
error(0, "WTP_INIT: machine_find_or_create: unhandled"
"event");
wap_event_dump(event);
break;
}
}
return machine;
}
/*
* Creates TR-Invoke.cnf event
*/
static WAPEvent *create_tr_invoke_cnf(WTPInitMachine *init_machine)
{
WAPEvent *event;
gw_assert(init_machine != NULL);
event = wap_event_create(TR_Invoke_Cnf);
event->u.TR_Invoke_Cnf.handle = init_machine->mid;
event->u.TR_Invoke_Cnf.addr_tuple =
wap_addr_tuple_duplicate(init_machine->addr_tuple);
return event;
}
/*
* Creates TR-Abort.ind event from an initiator state machine. In addtion, set
* the ir_flag on.
*/
static WAPEvent *create_tr_abort_ind(WTPInitMachine *sm, long abort_reason)
{
WAPEvent *event;
event = wap_event_create(TR_Abort_Ind);
event->u.TR_Abort_Ind.abort_code = abort_reason;
event->u.TR_Abort_Ind.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
event->u.TR_Abort_Ind.handle = sm->mid;
event->u.TR_Abort_Ind.ir_flag = INITIATOR_INDICATION;
return event;
}
static int tid_wrapped(unsigned short tid)
{
return tid > (1 << 15);
}
static unsigned short rcv_tid(unsigned short tid)
{
return tid ^ 0x8000;
}
/*
* Start retry interval timer (strictly speaking, timer iniatilised with retry
* interval). Multiply timer value with init_timer_freq.
*/
static void start_initiator_timer_R(WTPInitMachine *machine)
{
WAPEvent *timer_event;
int seconds;
timer_event = wap_event_create(TimerTO_R);
timer_event->u.TimerTO_R.handle = machine->mid;
if (machine->u_ack)
seconds = S_R_WITH_USER_ACK * init_timer_freq;
else
seconds = S_R_WITHOUT_USER_ACK * init_timer_freq;
gwtimer_start(machine->timer, seconds, timer_event);
}
static void stop_initiator_timer(Timer *timer)
{
debug("wap.wtp_init", 0, "stopping timer");
gw_assert(timer);
gwtimer_stop(timer);
}
static void send_abort(WTPInitMachine *machine, long type, long reason)
{
WAPEvent *e;
e = wtp_pack_abort(type, reason, machine->tid, machine->addr_tuple);
dispatch_to_wdp(e);
}
static void send_ack(WTPInitMachine *machine, long ack_type, int rid_flag)
{
WAPEvent *e;
e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple);
dispatch_to_wdp(e);
}
gateway-1.4.3/wap/wtls-secmgr.c 0000644 0001750 0001750 00000015437 11132672003 015425 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* gw/wtls-secmgr.c - wapbox wtls security manager
*
* The security manager's interface consists of two functions:
*
* wtls_secmgr_start()
* This starts the security manager thread.
*
* wtls_secmgr_dispatch(event)
* This adds a new event to the security manager's event
* queue.
*
* The wtls security manager is a thread that reads events from its event
* queue, and feeds back events to the WTLS layer. Here is where various
* approvals or rejections are made to requested security settings.
*
*/
#include
#include "gwlib/gwlib.h"
#if (HAVE_WTLS_OPENSSL)
#include "wtls.h"
/*
* Give the status the module:
*
* limbo
* not running at all
* running
* operating normally
* terminating
* waiting for operations to terminate, returning to limbo
*/
static enum { limbo, running, terminating } run_status = limbo;
/*
* The queue of incoming events.
*/
static List *secmgr_queue = NULL;
/*
* Private functions.
*/
static void main_thread(void *);
/***********************************************************************
* The public interface to the application layer.
*/
void wtls_secmgr_init(void) {
gw_assert(run_status == limbo);
secmgr_queue = gwlist_create();
gwlist_add_producer(secmgr_queue);
run_status = running;
gwthread_create(main_thread, NULL);
}
void wtls_secmgr_shutdown(void) {
gw_assert(run_status == running);
gwlist_remove_producer(secmgr_queue);
run_status = terminating;
gwthread_join_every(main_thread);
gwlist_destroy(secmgr_queue, wap_event_destroy_item);
}
void wtls_secmgr_dispatch(WAPEvent *event) {
gw_assert(run_status == running);
gwlist_produce(secmgr_queue, event);
}
long wtls_secmgr_get_load(void) {
gw_assert(run_status == running);
return gwlist_len(secmgr_queue);
}
/***********************************************************************
* Private functions.
*/
static void main_thread(void *arg) {
WAPEvent *ind, *res, *req, *term;
while (run_status == running && (ind = gwlist_consume(secmgr_queue)) != NULL) {
switch (ind->type) {
case SEC_Create_Ind:
/* Process the cipherlist */
/* Process the MAClist */
/* Process the PKIlist */
/* Dispatch a SEC_Create_Res */
res = wap_event_create(SEC_Create_Res);
res->u.SEC_Create_Res.addr_tuple =
wap_addr_tuple_duplicate(ind->u.SEC_Create_Ind.addr_tuple);
wtls_dispatch_event(res);
debug("wtls_secmgr : main_thread", 0,"Dispatching SEC_Create_Res event");
/* Dispatch a SEC_Exchange_Req or maybe a SEC_Commit_Req */
req = wap_event_create(SEC_Exchange_Req);
req->u.SEC_Exchange_Req.addr_tuple =
wap_addr_tuple_duplicate(ind->u.SEC_Create_Ind.addr_tuple);
wtls_dispatch_event(req);
debug("wtls_secmgr : main_thread", 0,"Dispatching SEC_Exchange_Req event");
wap_event_destroy(ind);
break;
case SEC_Terminate_Req:
/* Dispatch a SEC_Terminate_Req */
term = wap_event_create(SEC_Terminate_Req);
term->u.SEC_Terminate_Req.addr_tuple =
wap_addr_tuple_duplicate(ind->u.SEC_Create_Ind.addr_tuple);
term->u.SEC_Terminate_Req.alert_desc = 0;
term->u.SEC_Terminate_Req.alert_level = 3;
wtls_dispatch_event(term);
default:
panic(0, "WTLS-secmgr: Can't handle %s event",
wap_event_name(ind->type));
break;
}
}
}
#endif
gateway-1.4.3/wap/wsp_push_client_states.def 0000644 0001750 0001750 00000012774 11132672003 020264 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_push_client_states.def: Macros defining wsp push client state table
* rows.
* See documentation for guidance how to use and update these.
* 1 means an unconditional action, {} an ignored event.
*
* By Aarno Syvnen for Wapit Ltd.
*/
PUSH_CLIENT_STATE_NAME(PUSH_CLIENT_NULL_STATE)
PUSH_CLIENT_STATE_NAME(PUSH_CLIENT_RECEIVING)
ROW(PUSH_CLIENT_NULL_STATE,
TR_Invoke_Ind,
e->u.TR_Invoke_Ind.tcl == 1 && pdu->type == ConfirmedPush,
{
Octstr *push_body;
List *push_headers;
if (pdu->u.ConfirmedPush.headers_len > 0)
push_headers = wsp_headers_unpack(pdu->u.ConfirmedPush.headers, 0);
else
push_headers = NULL;
http_remove_hop_headers(push_headers);
http_header_pack(push_headers);
gw_assert(push_headers);
cpm->push_headers = http_header_duplicate(push_headers);
push_body = octstr_duplicate(pdu->u.ConfirmedPush.data);
http_destroy_headers(push_headers);
/*
* For debugging: just tell about the push OTA event, and destroy it here -
* handle_event does not do it.
*/
indicate_confirmedpush(cpm, push_body);
octstr_destroy(push_body);
/*
* For debugging: create S_ConfirmedPush_Res by ourselves and send it to
* ourselves.
*/
response_confirmedpush(cpm);
},
PUSH_CLIENT_RECEIVING)
ROW(PUSH_CLIENT_RECEIVING,
S_ConfirmedPush_Res,
1,
{
response_responder_invoke(cpm);
},
PUSH_CLIENT_NULL_STATE)
ROW(PUSH_CLIENT_RECEIVING,
S_PushAbort_Req,
1,
{
send_abort_to_responder(cpm, e->u.S_PushAbort_Req.reason);
indicate_pushabort(cpm, e->u.S_PushAbort_Req.reason);
},
PUSH_CLIENT_NULL_STATE)
ROW(PUSH_CLIENT_RECEIVING,
Abort_Event,
1,
{
send_abort_to_responder(cpm, e->u.S_PushAbort_Req.reason);
indicate_pushabort(cpm, WSP_ABORT_USERREQ);
},
PUSH_CLIENT_NULL_STATE)
ROW(PUSH_CLIENT_RECEIVING,
TR_Abort_Ind,
e->u.TR_Abort_Ind.abort_code == WSP_ABORT_DISCONNECT,
{
WAPEvent *wsp_event;
wsp_event = wap_event_create(Disconnect_Event);
wsp_event->u.Disconnect_Event.session_handle = cpm->client_push_id;
gwlist_append(push_client_queue, wsp_event);
},
PUSH_CLIENT_NULL_STATE)
ROW(PUSH_CLIENT_RECEIVING,
TR_Abort_Ind,
e->u.TR_Abort_Ind.abort_code == WSP_ABORT_SUSPEND,
{
WAPEvent *wsp_event;
wsp_event = wap_event_create(Suspend_Event);
wsp_event->u.Suspend_Event.session_handle = cpm->client_push_id;
gwlist_append(push_client_queue, wsp_event);
},
PUSH_CLIENT_NULL_STATE)
ROW(PUSH_CLIENT_RECEIVING,
TR_Abort_Ind,
e->u.TR_Abort_Ind.abort_code != WSP_ABORT_DISCONNECT &&
e->u.TR_Abort_Ind.abort_code != WSP_ABORT_SUSPEND,
{
indicate_pushabort(cpm, e->u.S_PushAbort_Req.reason);
},
PUSH_CLIENT_NULL_STATE)
#undef PUSH_CLIENT_STATE_NAME
#undef ROW
gateway-1.4.3/wap/cookies.h 0000644 0001750 0001750 00000007441 11132672003 014613 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* Module: cookies.h
*
* Description: Include module for cookies.c
*
* References: RFC 2109
*
* Author: Paul Keogh, ANAM Wireless Internet Solutions
*
* Date: May 2000
*/
#ifndef COOKIES_H
#define COOKIES_H
/* No support for Secure or Comment fields */
typedef struct _cookie {
Octstr *name;
Octstr *value;
Octstr *version;
Octstr *domain;
Octstr *path;
time_t max_age;
time_t birth;
} Cookie;
/* Function prototypes for external interface */
/*
* Memory management wrappers for cookies.
*/
Cookie *cookie_create(void);
void cookies_destroy(List*);
/*
* Parses the returned HTTP headers and adds the Cookie: headers to
* the cookie cache of the active WSPMachine.
* Returns: 0 on success, -1 on failure
*/
int get_cookies(List*, const WSPMachine*);
/*
* Adds the cookies from the WSPMachine cache to the outgoing HTTP request,
* rewriting the standard attributes and expiring the cookies if necessary.
* Returns: 0 on success, -1 on failure
*/
int set_cookies(List*, WSPMachine*);
#define MAX_HTTP_DATE_LENGTH 128
#endif
gateway-1.4.3/wap/wsp_server_session_machine.def 0000644 0001750 0001750 00000007211 11132672003 021107 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_server_session_machine.def - Define a WSP session machine.
*
* Lars Wirzenius
*/
#if !defined(HTTPHEADERS) || \
!defined(INTEGER) || \
!defined(OCTSTR) || \
!defined(ADDRTUPLE) || \
!defined(COOKIES) || \
!defined(MACHINESLIST) || \
!defined(CAPABILITIES) || \
!defined(MACHINE) || \
!defined(REFERER)
#error "Some required macro is missing."
#endif
MACHINE(
INTEGER(state)
INTEGER(connect_handle)
INTEGER(resume_handle)
INTEGER(session_id)
ADDRTUPLE(addr_tuple)
CAPABILITIES(request_caps)
CAPABILITIES(reply_caps)
INTEGER(MOR_push)
INTEGER(client_SDU_size)
INTEGER(encoding_version)
HTTPHEADERS(http_headers)
COOKIES(cookies)
REFERER(referer_url)
MACHINESLIST(methodmachines)
MACHINESLIST(pushmachines)
)
#undef INTEGER
#undef OCTSTR
#undef HTTPHEADERS
#undef ADDRTUPLE
#undef MACHINESLIST
#undef MACHINE
#undef COOKIES
#undef CAPABILITIES
#undef REFERER
gateway-1.4.3/wap/wtp_init_states.def 0000644 0001750 0001750 00000021010 11132672003 016672 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_init_state.h: Macro calls for implementing wtp initiator state tables
* See documentation for guidance how to use and update these.
*
* Only classes 0 and 1 are implemented. State NULL is called INITIATOR_NULL_
* STATE. 1 in the action field means that action is unconditional.
*
* Class 0 service is here a stateless invoke message (used for disconnection
* or unconfirmed push).
*
* Basic class 1 transaction, without timers, is following:
* - initiator sends an invoke message to the responder
* - responder acknowledges it, with an pdu with tid verification
* off (if it is on, we have a tid verification transaction,
* see below).
*
* Retransmission until acknowledgement is implemented using timers and
* retransmission counters. When the initiator sends an invoke it starts a
* timer. When it expires, it resends the packet (either ack or invoke), until
* counter reaches the maximum value. Then the transaction is aborted.
*
* If user acknowledgement is on, timers have different values.
*
* When the initiator aborts the transaction, it sends an abort pdu. When the
* responder does it, the initiator wtp user is indicated.
*
* Tid verification in the initiator means answering the question posed by the
* responder: "Have you an outstanding transaction having this tid". If we do
* not have it, we have already, before feeding the event into the state
* machine, sent an abort with reason INVALIDTID. So here we answer to an
* ack pdu with tidve-flag set with an ack pdu with tidok-flag set. See WTP
* 5.6, table 2; WTP 8.9; WTP 9.3.4.1.
*
* By Aarno Syvnen for Wapit Ltd.
*/
INIT_STATE_NAME(INITIATOR_NULL_STATE)
INIT_STATE_NAME(INITIATOR_RESULT_WAIT)
/*
* We do not use transaction class 2 here: Server is initiator only when it is
* pushing (class 1 or class 0) or disconnecting (class 0). First and second
* rows are similar, with exception of timer period.
*/
ROW(INITIATOR_NULL_STATE,
TR_Invoke_Req,
event->u.TR_Invoke_Req.tcl == 1,
{
WAPEvent *invoke;
/*
* A special counter is used for storing value used (1) for tidnew flag when
* restarting (See WTP 8.8.3.2)
*/
init_machine->tidnew = tidnew;
wap_event_destroy(init_machine->invoke);
init_machine->rid = 0;
init_machine->rcr = 0;
invoke = wtp_pack_invoke(init_machine, event);
init_machine->invoke = wap_event_duplicate(invoke);
dispatch_to_wdp(invoke);
init_machine->rid = 1;
/*
* Turn the tidnew-flag off if it was on. (This can happen when tid was
* wrapped or when we are restarting, see WTP 8.8.3.2)
*/
if (init_machine->tidnew) {
init_machine->tidnew = 0;
tidnew = 0;
}
init_machine->u_ack = event->u.TR_Invoke_Req.up_flag;
init_machine->rcr = 0;
start_initiator_timer_R(init_machine);
},
INITIATOR_RESULT_WAIT)
/*
* No need to turn tidnew flag when sending class 0 message; tid validation is
* not invoked in this case.
*/
ROW(INITIATOR_NULL_STATE,
TR_Invoke_Req,
event->u.TR_Invoke_Req.tcl == 0,
{
WAPEvent *invoke;
wap_event_destroy(init_machine->invoke);
invoke = wtp_pack_invoke(init_machine, event);
init_machine->invoke = wap_event_duplicate(invoke);
dispatch_to_wdp(invoke);
},
INITIATOR_NULL_STATE)
ROW(INITIATOR_RESULT_WAIT,
TR_Abort_Req,
1,
{
send_abort(init_machine, USER, event->u.TR_Abort_Req.abort_reason);
},
INITIATOR_NULL_STATE)
/*
* Neither we check transaction class here: this can only be acknowledgement of
* class 1 transaction.
*/
ROW(INITIATOR_RESULT_WAIT,
RcvAck,
event->u.RcvAck.tid_ok == 0,
{
stop_initiator_timer(init_machine->timer);
wsp_event = create_tr_invoke_cnf(init_machine);
dispatch_to_wsp(wsp_event);
},
INITIATOR_NULL_STATE)
/*
* This is a positive answer to a tid verification (negative one being
* already sent by init_machine_find_or_create).
*/
ROW(INITIATOR_RESULT_WAIT,
RcvAck,
event->u.RcvAck.tid_ok == 1 && init_machine->rcr < MAX_RCR,
{
send_ack(init_machine, TID_VERIFICATION, init_machine->rid);
init_machine->tidok_sent = 1;
++init_machine->rcr;
start_initiator_timer_R(init_machine);
},
INITIATOR_RESULT_WAIT)
/*
* RCR must not be greater than RCR_MAX. One of corrections from MOT_WTP_CR_01.
*/
ROW(INITIATOR_RESULT_WAIT,
RcvAck,
event->u.RcvAck.tid_ok,
{ },
INITIATOR_RESULT_WAIT)
ROW(INITIATOR_RESULT_WAIT,
RcvAbort,
1,
{
wsp_event = create_tr_abort_ind(init_machine,
event->u.RcvAbort.abort_reason);
dispatch_to_wsp(wsp_event);
},
INITIATOR_NULL_STATE)
ROW(INITIATOR_RESULT_WAIT,
RcvErrorPDU,
1,
{
send_abort(init_machine, USER, PROTOERR);
wsp_event = create_tr_abort_ind(init_machine, PROTOERR);
dispatch_to_wsp(wsp_event);
},
INITIATOR_NULL_STATE)
ROW(INITIATOR_RESULT_WAIT,
TimerTO_R,
init_machine->rcr < MAX_RCR && !init_machine->tidok_sent,
{
WAPEvent *resend;
++init_machine->rcr;
start_initiator_timer_R(init_machine);
resend = wap_event_duplicate(init_machine->invoke);
wtp_pack_set_rid(resend, init_machine->rid);
dispatch_to_wdp(resend);
},
INITIATOR_RESULT_WAIT)
ROW(INITIATOR_RESULT_WAIT,
TimerTO_R,
init_machine->rcr < MAX_RCR && init_machine->tidok_sent,
{
++init_machine->rcr;
start_initiator_timer_R(init_machine);
send_ack(init_machine, TID_VERIFICATION, init_machine->tidok_sent);
},
INITIATOR_RESULT_WAIT)
ROW(INITIATOR_RESULT_WAIT,
TimerTO_R,
init_machine->rcr == MAX_RCR,
{
wsp_event = create_tr_abort_ind(init_machine, NORESPONSE);
dispatch_to_wsp(wsp_event);
},
INITIATOR_NULL_STATE)
#undef ROW
#undef INIT_STATE_NAME
gateway-1.4.3/wap/wtls_pdusupport.c 0000644 0001750 0001750 00000110560 11132672002 016444 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtls_support.c: pack and unpack WTLS packets
*
* Support functions for packing and unpacking PDUs
*
*/
#include "gwlib/gwlib.h"
#if (HAVE_WTLS_OPENSSL)
#include "wtls_pdu.h"
#include "wtls_pdusupport.h"
#include "wtls_statesupport.h"
// Change this later !!!!
extern PublicKeyAlgorithm public_key_algo;
extern SignatureAlgorithm signature_algo;
/*****************************************************************
* PACK functions
*/
int pack_int16(Octstr *data, long charpos, int i) {
octstr_append_char(data, (i & 0xFF00) >> 8);
charpos += 1;
octstr_append_char(data, i & 0x00FF);
charpos += 1;
return charpos;
}
int pack_int32(Octstr *data, long charpos, long i) {
charpos = pack_int16(data, charpos, (i & 0xFFFF0000) >> 16);
charpos = pack_int16(data, charpos, i & 0xFFFF);
return charpos;
}
int pack_octstr(Octstr *data, long charpos, Octstr *opaque) {
octstr_append_char(data, octstr_len(opaque));
charpos += 1;
octstr_insert(data, opaque, octstr_len(data));
charpos += octstr_len(opaque);
return charpos;
}
int pack_octstr16(Octstr *data, long charpos, Octstr *opaque) {
charpos += pack_int16(data, charpos, octstr_len(opaque));
octstr_insert(data, opaque, octstr_len(data));
charpos += octstr_len(opaque);
return charpos;
}
int pack_octstr_fixed(Octstr *data, long charpos, Octstr *opaque) {
octstr_insert(data, opaque, octstr_len(data));
charpos += octstr_len(opaque);
return charpos;
}
int pack_random(Octstr *data, long charpos, Random *random) {
charpos = pack_int32(data, charpos, random->gmt_unix_time);
charpos = pack_octstr_fixed(data, charpos, random->random_bytes);
return charpos;
}
int pack_dhparams(Octstr *data, long charpos, DHParameters *dhparams) {
octstr_append_char(data, dhparams->dh_e);
charpos += 1;
charpos = pack_octstr16(data, charpos, dhparams->dh_p);
charpos = pack_octstr16(data, charpos, dhparams->dh_g);
return charpos;
}
int pack_ecparams(Octstr *data, long charpos, ECParameters *ecparams) {
/* field */
octstr_append_char(data, ecparams->field);
charpos += 1;
switch (ecparams->field) {
case ec_prime_p:
charpos = pack_octstr(data, charpos, ecparams->prime_p);
break;
case ec_characteristic_two:
/* m (16 bits) */
charpos = pack_int16(data, charpos, ecparams->m);
/* basis */
octstr_append_char(data, ecparams->basis);
charpos += 1;
switch (ecparams->basis) {
case ec_basis_onb:
break;
case ec_basis_trinomial:
charpos = pack_int16(data, charpos, ecparams->k);
break;
case ec_basis_pentanomial:
charpos = pack_int16(data, charpos, ecparams->k1);
charpos = pack_int16(data, charpos, ecparams->k2);
charpos = pack_int16(data, charpos, ecparams->k3);
break;
case ec_basis_polynomial:
charpos = pack_octstr(data, charpos, ecparams->irreducible);
break;
}
break;
}
/* pack the ECCurve */
charpos = pack_octstr(data, charpos, ecparams->curve->a);
charpos = pack_octstr(data, charpos, ecparams->curve->b);
charpos = pack_octstr(data, charpos, ecparams->curve->seed);
/* pack the ECPoint */
charpos = pack_octstr(data, charpos, ecparams->base->point);
/* order and cofactor */
charpos = pack_octstr(data, charpos, ecparams->order);
charpos = pack_octstr(data, charpos, ecparams->cofactor);
return charpos;
}
int pack_param_spec(Octstr *data, long charpos, ParameterSpecifier *pspec) {
if (pspec == NULL)
{
octstr_append_char(data, 0);
charpos += 1;
return charpos;
}
/* index */
octstr_append_char(data, pspec->param_index);
charpos += 1;
/* ParameterSet struct */
octstr_append_char(data, pspec->param_set->length);
charpos += 1;
switch (public_key_algo) {
case diffie_hellman_pubkey:
pack_dhparams(data, charpos, pspec->param_set->dhparams);
break;
case elliptic_curve_pubkey:
pack_ecparams(data, charpos, pspec->param_set->ecparams);
break;
}
return charpos;
}
int pack_public_key(Octstr *data, long charpos, PublicKey *key, PublicKeyType key_type) {
switch (key_type) {
case ecdh_key:
charpos = pack_octstr(data, charpos, key->ecdh_pubkey->point);
break;
case ecdsa_key:
charpos = pack_octstr(data, charpos, key->ecdsa_pubkey->point);
break;
case rsa_key:
charpos = pack_rsa_pubkey(data, charpos, key->rsa_pubkey);
break;
}
return charpos;
}
int pack_rsa_pubkey(Octstr *data, long charpos, RSAPublicKey *key) {
charpos = pack_octstr16(data, charpos, key->rsa_exponent);
charpos = pack_octstr16(data, charpos, key->rsa_modulus);
return charpos;
}
int pack_ec_pubkey(Octstr *data, long charpos, ECPublicKey *key) {
charpos = pack_octstr(data, charpos, key->point);
return charpos;
}
int pack_dh_pubkey(Octstr *data, long charpos, DHPublicKey *key) {
charpos = pack_octstr16(data, charpos, key->dh_Y);
return charpos;
}
int pack_rsa_secret(Octstr *data, long charpos, RSASecret *secret) {
octstr_append_char(data, secret->client_version);
charpos += 1;
charpos = pack_array(data, charpos, secret->random);
return charpos;
}
int pack_rsa_encrypted_secret(Octstr *data, long charpos, RSAEncryptedSecret *secret) {
charpos = pack_octstr16(data, charpos, secret->encrypted_secret);
return charpos;
}
int pack_key_exchange_id(Octstr *data, long charpos, KeyExchangeId *keyexid) {
octstr_set_char(data, charpos, keyexid->key_exchange_suite);
charpos += 1;
charpos = pack_param_spec(data, charpos, keyexid->param_specif);
charpos = pack_identifier(data, charpos, keyexid->identifier);
return charpos;
}
int pack_array(Octstr *data, long charpos, List *array) {
int i;
long pos = 0;
Octstr *buffer;
/* we need to know the length in bytes of the list
so we pack everything in a buffer for now. */
buffer = octstr_create("");
/* pack each entry in the buffer */
for (i=0; ibulk_cipher_algo);
charpos += 1;
octstr_set_char(data, charpos, cs->mac_algo);
charpos += 1;
}
return charpos;
}
int pack_compression_method_list(Octstr *data, long charpos, List *compmethod_list) {
int i;
/* vector starts with its length */
octstr_set_char(data, charpos, gwlist_len(compmethod_list));
charpos += 1;
/* pack the CompressionMethods */
for (i=0; iid_type) {
case text:
octstr_set_char(data, charpos, ident->charset);
charpos += 1;
charpos = pack_octstr(data, charpos, ident->name);
break;
case binary:
charpos = pack_octstr(data, charpos, ident->identifier);
break;
case key_hash_sha:
charpos = pack_octstr(data, charpos, ident->key_hash);
break;
case x509_name:
charpos = pack_octstr(data, charpos, ident->distinguished_name);
break;
}
return charpos;
}
int pack_signature(Octstr *data, long charpos, Signature *sig) {
switch (signature_algo) {
case ecdsa_sha:
case rsa_sha:
charpos = pack_array(data, charpos, sig->sha_hash);
break;
}
return charpos;
}
int pack_wtls_certificate(Octstr *data, long charpos, WTLSCertificate *cert) {
/* === pack ToBeSignedCertificate === */
/* version */
octstr_set_char(data, charpos, cert->tobesigned_cert->certificate_version);
charpos += 1;
/* sig algo */
octstr_set_char(data, charpos, cert->tobesigned_cert->signature_algo);
charpos += 1;
/* identifier */
octstr_set_char(data, charpos, cert->tobesigned_cert->issuer->id_type);
charpos += 1;
/* issuer Identifier */
charpos = pack_identifier(data, charpos, cert->tobesigned_cert->issuer);
/* validity periods */
charpos = pack_int32(data, charpos, cert->tobesigned_cert->valid_not_before);
charpos = pack_int32(data, charpos, cert->tobesigned_cert->valid_not_after);
/* subject Identifier */
charpos = pack_identifier(data, charpos, cert->tobesigned_cert->subject);
/* public_key_type */
octstr_set_char(data, charpos, cert->tobesigned_cert->pubkey_type);
charpos += 1;
/* parameter specifier */
charpos = pack_param_spec(data, charpos, cert->tobesigned_cert->param_spec);
/* public key */
charpos = pack_public_key(data, charpos, cert->tobesigned_cert->pubkey,
cert->tobesigned_cert->pubkey_type);
/* === pack Signature === */
charpos = pack_signature(data, charpos, cert->signature);
return charpos;
}
/*****************************************************************
* UNPACK functions
*/
int unpack_int16(Octstr *data, long *charpos) {
int n;
n = octstr_get_char(data, *charpos) << 8;
*charpos += 1;
n += octstr_get_char(data, *charpos);
*charpos += 1;
return n;
}
long unpack_int32(Octstr *data, long *charpos) {
int n;
n = octstr_get_char(data, *charpos);
n = n << 8;
*charpos += 1;
n += octstr_get_char(data, *charpos);
n = n << 8;
*charpos += 1;
n += octstr_get_char(data, *charpos);
n = n << 8;
*charpos += 1;
n += octstr_get_char(data, *charpos);
*charpos += 1;
return n;
}
Octstr * unpack_octstr(Octstr *data, long *charpos) {
int length;
Octstr *opaque;
length = octstr_get_char(data, *charpos);
*charpos += 1;
opaque = octstr_copy(data, *charpos, length);
*charpos += length;
return opaque;
}
Octstr * unpack_octstr16(Octstr *data, long *charpos) {
long length;
Octstr *opaque;
length = unpack_int16(data, charpos);
opaque = octstr_copy(data, *charpos, length);
*charpos += length;
return opaque;
}
Octstr * unpack_octstr_fixed(Octstr *data, long *charpos, long length) {
Octstr *opaque;
opaque = octstr_copy(data, *charpos, length);
*charpos += length;
return opaque;
}
Random * unpack_random(Octstr *data, long *charpos) {
Random *random;
/* create the Random structure */
random = (Random *)gw_malloc(sizeof(Random));
random->gmt_unix_time = unpack_int32(data, charpos);
random->random_bytes = unpack_octstr_fixed(data, charpos, 12);
return random;
}
DHParameters * unpack_dhparams(Octstr *data, long *charpos) {
DHParameters *dhparams;
/* create the DHParameters */
dhparams = (DHParameters *)gw_malloc(sizeof(DHParameters));
dhparams->dh_e = octstr_get_char(data, *charpos);
*charpos += 1;
dhparams->dh_p = unpack_octstr16(data, charpos);
dhparams->dh_g = unpack_octstr16(data, charpos);
return dhparams;
}
ECParameters * unpack_ecparams(Octstr *data, long *charpos) {
ECParameters *ecparams;
/* create the ECParameters */
ecparams = (ECParameters *)gw_malloc(sizeof(ECParameters));
/* field */
ecparams->field = octstr_get_char(data, *charpos);
*charpos += 1;
switch (ecparams->field) {
case ec_prime_p:
ecparams->prime_p = unpack_octstr(data, charpos);
break;
case ec_characteristic_two:
/* m (16 bits) */
ecparams->m = unpack_int16(data, charpos);
/* basis */
ecparams->basis = octstr_get_char(data, *charpos);
*charpos += 1;
switch (ecparams->basis) {
case ec_basis_onb:
break;
case ec_basis_trinomial:
ecparams->k = unpack_int16(data, charpos);
break;
case ec_basis_pentanomial:
ecparams->k1 = unpack_int16(data, charpos);
ecparams->k2 = unpack_int16(data, charpos);
ecparams->k3 = unpack_int16(data, charpos);
break;
case ec_basis_polynomial:
ecparams->irreducible = unpack_octstr(data, charpos);
break;
}
break;
}
/* pack the ECCurve */
ecparams->curve->a = unpack_octstr(data, charpos);
ecparams->curve->b = unpack_octstr(data, charpos);
ecparams->curve->seed = unpack_octstr(data, charpos);
/* pack the ECPoint */
ecparams->base->point = unpack_octstr(data, charpos);
/* order and cofactor */
ecparams->order = unpack_octstr(data, charpos);
ecparams->cofactor = unpack_octstr(data, charpos);
return ecparams;
}
ParameterSpecifier * unpack_param_spec(Octstr *data, long *charpos) {
ParameterSpecifier *pspec;
/* create the ParameterSpecifier */
pspec = (ParameterSpecifier *)gw_malloc(sizeof(ParameterSpecifier));
/* index */
pspec->param_index = octstr_get_char(data, *charpos);
*charpos += 1;
/* ParameterSet struct */
if(pspec->param_index == 255) {
pspec->param_set = (ParameterSet *)gw_malloc(sizeof(ParameterSet));
pspec->param_set->length = octstr_get_char(data, *charpos);
*charpos += 1;
switch (public_key_algo) {
case diffie_hellman_pubkey:
pspec->param_set->dhparams = unpack_dhparams(data, charpos);
break;
case elliptic_curve_pubkey:
pspec->param_set->ecparams = unpack_ecparams(data, charpos);
break;
}
}
return pspec;
}
RSAPublicKey * unpack_rsa_pubkey(Octstr *data, long *charpos) {
RSAPublicKey *key;
/* create the RSAPublicKey */
key = (RSAPublicKey *)gw_malloc(sizeof(RSAPublicKey));
key->rsa_exponent = unpack_octstr16( data, charpos);
key->rsa_modulus = unpack_octstr16( data, charpos);
return key;
}
DHPublicKey * unpack_dh_pubkey(Octstr *data, long *charpos) {
DHPublicKey *key;
/* create the DHPublicKey */
key = (DHPublicKey *)gw_malloc(sizeof(DHPublicKey));
key->dh_Y = unpack_octstr16( data, charpos);
return key;
}
ECPublicKey * unpack_ec_pubkey(Octstr *data, long *charpos) {
ECPublicKey *key;
/* create the ECPublicKey */
key = (ECPublicKey *)gw_malloc(sizeof(ECPublicKey));
key->point = unpack_octstr( data, charpos);
return key;
}
RSASecret * unpack_rsa_secret(Octstr *data, long *charpos) {
RSASecret *secret;
/* create the RSASecret */
secret = (RSASecret *)gw_malloc(sizeof(RSASecret));
secret->client_version = octstr_get_char(data, *charpos);
*charpos += 1;
secret->random = unpack_array(data, charpos);
return secret;
}
RSAEncryptedSecret * unpack_rsa_encrypted_secret(Octstr *data, long *charpos) {
RSAEncryptedSecret *secret;
/* create the RSASecret */
secret = (RSAEncryptedSecret *)gw_malloc(sizeof(RSAEncryptedSecret));
//secret->encrypted_secret = unpack_octstr16(data, charpos);
secret->encrypted_secret = unpack_octstr_fixed(data, charpos, octstr_len(data) - *charpos);
return secret;
}
PublicKey * unpack_public_key(Octstr *data, long *charpos, PublicKeyType key_type) {
PublicKey *key;
/* create the PublicKey */
key = (PublicKey *)gw_malloc(sizeof(PublicKey));
switch (key_type) {
case ecdh_key:
key->ecdh_pubkey = unpack_ec_pubkey(data, charpos);
break;
case ecdsa_key:
key->ecdsa_pubkey = unpack_ec_pubkey(data, charpos);
break;
case rsa_key:
key->rsa_pubkey = unpack_rsa_pubkey(data, charpos);
break;
}
return key;
}
KeyExchangeId * unpack_key_exchange_id(Octstr *data, long *charpos) {
KeyExchangeId *keyexid;
/* create the KeyExchangeID */
keyexid = (KeyExchangeId *)gw_malloc(sizeof(KeyExchangeId));
keyexid->key_exchange_suite = octstr_get_char(data, *charpos);
*charpos += 1;
keyexid->param_specif = unpack_param_spec(data, charpos);
keyexid->identifier = unpack_identifier(data, charpos);
return keyexid;
}
List * unpack_array(Octstr *data, long *charpos) {
int i;
int array_length;
List *array;
/* create the list */
array = gwlist_create();
/* get the size of the array */
array_length = octstr_get_char(data, *charpos);
*charpos += 1;
/* store each entry in the list */
for (i=0; ibulk_cipher_algo = octstr_get_char(data, *charpos);
*charpos += 1;
cs->mac_algo = octstr_get_char(data, *charpos);
*charpos += 1;
gwlist_append(ciphersuites, (void *)cs);
}
return ciphersuites;
}
List * unpack_compression_method_list(Octstr *data, long *charpos) {
List *compmethod_list;
int gwlist_length;
int i;
CompressionMethod *cm;
/* create the list */
compmethod_list = gwlist_create();
/* get the size of the array */
gwlist_length = octstr_get_char(data, *charpos);
*charpos += 1;
/* unpack the CompressionMethods */
for (i=0; iid_type = octstr_get_char(data, *charpos);
*charpos += 1;
switch (ident->id_type) {
case text:
ident->charset = octstr_get_char(data, *charpos);
*charpos += 1;
ident->name = unpack_octstr(data, charpos);
break;
case binary:
ident->identifier = unpack_octstr(data, charpos);
break;
case key_hash_sha:
ident->key_hash = unpack_octstr(data, charpos);
break;
case x509_name:
ident->distinguished_name = unpack_octstr(data, charpos);
break;
}
return ident;
}
Signature * unpack_signature(Octstr *data, long *charpos) {
Signature *sig;
/* create Signature */
sig = (Signature *)gw_malloc(sizeof(Signature));
switch (signature_algo) {
case ecdsa_sha:
case rsa_sha:
sig->sha_hash = unpack_array(data, charpos);
break;
}
return sig;
}
WTLSCertificate * unpack_wtls_certificate(Octstr *data, long *charpos) {
WTLSCertificate *cert;
/* create the Certificate */
cert = (WTLSCertificate *)gw_malloc(sizeof(WTLSCertificate));
/* === unpack ToBeSignedCertificate === */
cert->tobesigned_cert = (ToBeSignedCertificate *)gw_malloc(sizeof(ToBeSignedCertificate));
/* version */
cert->tobesigned_cert->certificate_version = octstr_get_char(data, *charpos);
*charpos += 1;
/* sig algo */
cert->tobesigned_cert->signature_algo = octstr_get_char(data, *charpos);
*charpos += 1;
/* identifier */
cert->tobesigned_cert->issuer->id_type = octstr_get_char(data, *charpos);
*charpos += 1;
/* issuer Identifier */
cert->tobesigned_cert->issuer = unpack_identifier(data, charpos);
/* validity periods */
cert->tobesigned_cert->valid_not_before = unpack_int32(data, charpos);
cert->tobesigned_cert->valid_not_after = unpack_int32(data, charpos);
/* subject Identifier */
cert->tobesigned_cert->subject = unpack_identifier(data, charpos);
/* public_key_type */
cert->tobesigned_cert->pubkey_type = octstr_get_char(data, *charpos);
*charpos += 1;
/* parameter specifier */
cert->tobesigned_cert->param_spec = unpack_param_spec(data, charpos);
/* public key */
cert->tobesigned_cert->pubkey = unpack_public_key(data, charpos,
cert->tobesigned_cert->pubkey_type);
/* === pack Signature === */
cert->signature = unpack_signature(data, charpos);
return cert;
}
/*****************************************************************
* DESTROY functions
*/
void destroy_octstr(Octstr *data) {
octstr_destroy(data);
}
void destroy_octstr16(Octstr *data) {
octstr_destroy(data);
}
void destroy_octstr_fixed(Octstr *data) {
octstr_destroy(data);
}
void destroy_random(Random *random) {
octstr_destroy(random->random_bytes);
gw_free(random);
}
void destroy_dhparams(DHParameters *dhparams) {
destroy_octstr16(dhparams->dh_p);
destroy_octstr16(dhparams->dh_g);
gw_free(dhparams);
}
void destroy_ecparams(ECParameters *ecparams) {
/* field */
switch (ecparams->field) {
case ec_prime_p:
octstr_destroy(ecparams->prime_p);
break;
case ec_characteristic_two:
switch (ecparams->basis) {
case ec_basis_onb:
break;
case ec_basis_trinomial:
break;
case ec_basis_pentanomial:
break;
case ec_basis_polynomial:
octstr_destroy(ecparams->irreducible);
break;
}
break;
}
/* pack the ECCurve */
octstr_destroy(ecparams->curve->a);
octstr_destroy(ecparams->curve->b);
octstr_destroy(ecparams->curve->seed);
/* pack the ECPoint */
octstr_destroy(ecparams->base->point);
/* order and cofactor */
octstr_destroy(ecparams->order);
octstr_destroy(ecparams->cofactor);
gw_free(ecparams);
}
void destroy_param_spec(ParameterSpecifier *pspec) {
switch (public_key_algo) {
case diffie_hellman_pubkey:
destroy_dhparams(pspec->param_set->dhparams);
break;
case elliptic_curve_pubkey:
destroy_ecparams(pspec->param_set->ecparams);
break;
}
gw_free(pspec);
}
void destroy_public_key(PublicKey *key) {
if(key->ecdh_pubkey)
{
octstr_destroy(key->ecdh_pubkey->point);
gw_free(key->ecdh_pubkey);
}
if(key->ecdsa_pubkey)
{
octstr_destroy(key->ecdsa_pubkey->point);
gw_free(key->ecdsa_pubkey);
}
if(key->rsa_pubkey)
{
destroy_rsa_pubkey(key->rsa_pubkey);
}
gw_free(key);
}
void destroy_rsa_pubkey(RSAPublicKey *key) {
octstr_destroy(key->rsa_exponent);
octstr_destroy(key->rsa_modulus);
gw_free(key);
}
void destroy_ec_pubkey(ECPublicKey *key) {
octstr_destroy(key->point);
gw_free(key);
}
void destroy_dh_pubkey(DHPublicKey *key) {
octstr_destroy(key->dh_Y);
gw_free(key);
}
void destroy_rsa_secret(RSASecret *secret) {
destroy_array(secret->random);
gw_free(secret);
}
void destroy_rsa_encrypted_secret(RSAEncryptedSecret *secret) {
octstr_destroy(secret->encrypted_secret);
gw_free(secret);
}
void destroy_key_exchange_id(KeyExchangeId *keyexid) {
destroy_param_spec(keyexid->param_specif);
destroy_identifier(keyexid->identifier);
gw_free(keyexid);
}
void destroy_array(List *array) {
int i;
/* pack each entry in the array */
for (i=0; iid_type) {
case text:
octstr_destroy(ident->name);
break;
case binary:
octstr_destroy(ident->identifier);
break;
case key_hash_sha:
octstr_destroy(ident->key_hash);
break;
case x509_name:
octstr_destroy(ident->distinguished_name);
break;
}
gw_free(ident);
}
void destroy_signature(Signature *sig) {
switch (signature_algo) {
case ecdsa_sha:
case rsa_sha:
destroy_array(sig->sha_hash);
break;
}
gw_free(sig);
}
void destroy_wtls_certificate(WTLSCertificate *cert) {
/* === destroy ToBeSignedCertificate === */
/* issuer Identifier */
destroy_identifier(cert->tobesigned_cert->issuer);
/* subject Identifier */
destroy_identifier(cert->tobesigned_cert->subject);
/* parameter specifier */
destroy_param_spec(cert->tobesigned_cert->param_spec);
/* public key */
destroy_public_key(cert->tobesigned_cert->pubkey);
/* === destroy Signature === */
destroy_signature(cert->signature);
gw_free(cert);
}
/*****************************************************************
* DUMP functions
*/
void dump_void16(unsigned char *dbg, int level, int i) {
debug(dbg, 0, "%*s16 bit Int: %p", level, "", i);
}
void dump_int32(unsigned char *dbg, int level, long i) {
debug(dbg, 0, "%*s32 bit Int: %p", level, "", i);
}
void dump_octstr(unsigned char *dbg, int level, Octstr *opaque) {
octstr_dump(opaque, 0);
}
void dump_octstr16(unsigned char *dbg, int level, Octstr *opaque) {
octstr_dump(opaque, 0);
}
void dump_octstr_fixed(unsigned char *dbg, int level, Octstr *opaque) {
octstr_dump(opaque, 0);
}
void dump_random(unsigned char *dbg, int level, Random *random) {
debug(dbg, 0, "%*sRandom :", level, "");
debug(dbg, 0, "%*sGMT Unix Time: %p", level+1, "", random->gmt_unix_time);
debug(dbg, 0, "%*sRandom Bytes:", level+1, "");
dump_octstr_fixed(dbg, level+2, random->random_bytes);
}
void dump_dhparams(unsigned char *dbg, int level, DHParameters *dhparams) {
debug(dbg, 0, "%*sDH Parameters :", level, "");
debug(dbg, 0, "%*sdh_e: %p", level+1, "", dhparams->dh_e);
debug(dbg, 0, "%*sdh_p:", level+1, "");
dump_octstr16(dbg, level+2, dhparams->dh_p);
debug(dbg, 0, "%*sdh_g:", level+1, "");
dump_octstr16(dbg, level+2, dhparams->dh_g);
}
void dump_ecparams(unsigned char *dbg, int level, ECParameters *ecparams) {
debug(dbg, 0, "%*sEC Parameters :", level, "");
/* field */
debug(dbg, 0, "%*sField: %p", level+1, "", ecparams->field);
switch (ecparams->field) {
case ec_prime_p:
debug(dbg, 0, "%*sprime_p :", level+1, "");
dump_octstr(dbg, level+1, ecparams->prime_p);
break;
case ec_characteristic_two:
/* m (16 bits) */
debug(dbg, 0, "%*sM: %p", level+1, "", ecparams->m);
/* basis */
debug(dbg, 0, "%*sBasis: %p", level+1, "", ecparams->basis);
switch (ecparams->basis) {
case ec_basis_onb:
break;
case ec_basis_trinomial:
debug(dbg, 0, "%*sK: %p", level+1, "", ecparams->k);
break;
case ec_basis_pentanomial:
debug(dbg, 0, "%*sk1: %p", level+1, "", ecparams->k1);
debug(dbg, 0, "%*sk2: %p", level+1, "", ecparams->k2);
debug(dbg, 0, "%*sk3: %p", level+1, "", ecparams->k3);
break;
case ec_basis_polynomial:
debug(dbg, 0, "%*sirreducible: %p", level+1, "");
dump_octstr(dbg, level+1, ecparams->irreducible);
break;
}
break;
}
/* pack the ECCurve */
debug(dbg, 0, "%*sEC Curve: %p", level+1, "");
debug(dbg, 0, "%*sa: %p", level+2, "");
dump_octstr(dbg, level+2, ecparams->curve->a);
debug(dbg, 0, "%*sb: %p", level+2, "");
dump_octstr(dbg, level+2, ecparams->curve->b);
debug(dbg, 0, "%*sseed: %p", level+2, "");
dump_octstr(dbg, level+2, ecparams->curve->seed);
/* pack the ECPoint */
debug(dbg, 0, "%*spoint: %p", level+2, "");
dump_octstr(dbg, level+2, ecparams->base->point);
/* order and cofactor */
debug(dbg, 0, "%*sorder: %p", level+2, "");
dump_octstr(dbg, level+2, ecparams->order);
debug(dbg, 0, "%*scofactor: %p", level+2, "");
dump_octstr(dbg, level+2, ecparams->cofactor);
}
void dump_param_spec(unsigned char *dbg, int level, ParameterSpecifier *pspec) {
debug(dbg, 0, "%*sParameterSpecifier:", level, "");
/* index */
debug(dbg, 0, "%*sParameter Index: %d", level+1, "", pspec->param_index);
/* ParameterSet struct */
if(pspec->param_index == 255) {
debug(dbg, 0, "%*sLength: %p", level+1, "", pspec->param_set->length);
switch (public_key_algo) {
case diffie_hellman_pubkey:
dump_dhparams(dbg, level+1, pspec->param_set->dhparams);
break;
case elliptic_curve_pubkey:
dump_ecparams(dbg, level+1, pspec->param_set->ecparams);
break;
}
}
}
void dump_public_key(unsigned char *dbg, int level, PublicKey *key, PublicKeyType key_type) {
switch (key_type) {
case ecdh_key:
debug(dbg, 0, "%*sPublicKey: %p", level, "");
debug(dbg, 0, "%*sECDH Point: %p", level+1, "");
dump_octstr(dbg, level+1, key->ecdh_pubkey->point);
break;
case ecdsa_key:
debug(dbg, 0, "%*sECDSA Point: %p", level+1, "");
dump_octstr(dbg, level+1, key->ecdsa_pubkey->point);
break;
case rsa_key:
dump_rsa_pubkey(dbg, level+1, key->rsa_pubkey);
break;
}
}
void dump_rsa_pubkey(unsigned char *dbg, int level, RSAPublicKey *key) {
debug(dbg, 0, "%*sRSA Public Key: %p", level, "");
debug(dbg, 0, "%*sRSA Exponent: %p", level+1, "");
dump_octstr(dbg, level+2, key->rsa_exponent);
debug(dbg, 0, "%*sRSA Modulus: %p", level+1, "");
dump_octstr(dbg, level+2, key->rsa_modulus);
}
void dump_ec_pubkey(unsigned char *dbg, int level, ECPublicKey *key) {
debug(dbg, 0, "%*sEC Public Key: %p", level, "");
debug(dbg, 0, "%*sPoint: %p", level+1, "");
dump_octstr(dbg, level+2, key->point);
}
void dump_dh_pubkey(unsigned char *dbg, int level, DHPublicKey *key) {
debug(dbg, 0, "%*sDH Public Key: %p", level, "");
dump_octstr(dbg, level+2, key->dh_Y);
}
void dump_rsa_secret(unsigned char *dbg, int level, RSASecret *secret) {
debug(dbg, 0, "%*sRSA Secret: %p", level, "");
debug(dbg, 0, "%*sClient Version: %p", level+1, "", secret->client_version);
debug(dbg, 0, "%*sRandom: %p", level, "");
dump_array(dbg, level+2, secret->random);
}
void dump_rsa_encrypted_secret(unsigned char *dbg, int level, RSAEncryptedSecret *secret) {
debug(dbg, 0, "%*sRSA Encrypted Secret: %p", level, "");
dump_octstr(dbg, level+1, secret->encrypted_secret);
}
void dump_key_exchange_id(unsigned char *dbg, int level, KeyExchangeId *keyexid) {
debug(dbg, 0, "%*sKey Exchange Id:", level, "");
debug(dbg, 0, "%*sKey Exch Suite: %d", level+1, "", keyexid->key_exchange_suite);
dump_param_spec(dbg, level+1, keyexid->param_specif);
dump_identifier(dbg, level+1, keyexid->identifier);
}
void dump_array(unsigned char *dbg, int level, List *array) {
int i;
/*debug(dbg, 0, "%*sOctstr Array: %p", level, "");*/
/* dump each entry in the array */
for (i=0; ibulk_cipher_algo);
debug(dbg, 0, "%*sMAC Algo: %p", level, "", cs->mac_algo);
}
}
void dump_compression_method_list(unsigned char *dbg, int level, List *compmethod_list) {
int i;
debug(dbg, 0, "%*sCompression Method List: %p", level, "");
/* pack the CompressionMethods */
for (i=0; iid_type);
switch (ident->id_type) {
case text:
debug(dbg, 0, "%*sCharset: %p", level+1, "", ident->charset);
debug(dbg, 0, "%*sNamet: %p", level+1, "", ident->name);
break;
case binary:
debug(dbg, 0, "%*sIdentifier: %p", level+1, "");
dump_octstr(dbg, level+2, ident->identifier);
break;
case key_hash_sha:
debug(dbg, 0, "%*sKey Hash: %p", level+1, "");
dump_octstr(dbg, level+2, ident->key_hash);
break;
case x509_name:
debug(dbg, 0, "%*sDistinguished Name: %p", level+1, "");
dump_octstr(dbg, level+2, ident->distinguished_name);
break;
}
}
void dump_signature(unsigned char *dbg, int level, Signature *sig) {
debug(dbg, 0, "%*sSignature: %p", level, "");
switch (signature_algo) {
case ecdsa_sha:
case rsa_sha:
dump_array(dbg, level+1, sig->sha_hash);
break;
}
}
void dump_wtls_certificate(unsigned char *dbg, int level, WTLSCertificate *cert) {
debug(dbg, 0, "%*sWTLS Certificate: %p", level, "");
/* === pack ToBeSignedCertificate === */
/* version */
debug(dbg, 0, "%*sCertificate Version: %p", level+1, "", cert->tobesigned_cert->certificate_version);
/* sig algo */
debug(dbg, 0, "%*sSignature Algo: %p", level+1, "", cert->tobesigned_cert->signature_algo);
/* identifier */
debug(dbg, 0, "%*sID Type: %p", level+1, "", cert->tobesigned_cert->issuer->id_type);
/* issuer Identifier */
dump_identifier(dbg, level+1, cert->tobesigned_cert->issuer);
/* validity periods */
debug(dbg, 0, "%*sValid not Before: %p", level+1, "", cert->tobesigned_cert->valid_not_before);
debug(dbg, 0, "%*sValid not After: %p", level+1, "", cert->tobesigned_cert->valid_not_after);
/* subject Identifier */
dump_identifier(dbg, level+1, cert->tobesigned_cert->subject);
/* public_key_type */
debug(dbg, 0, "%*sPublic Key Type: %p", level+1, "", cert->tobesigned_cert->pubkey_type);
/* parameter specifier */
dump_param_spec(dbg, level+1, cert->tobesigned_cert->param_spec);
/* public key */
dump_public_key(dbg, level+1, cert->tobesigned_cert->pubkey,
cert->tobesigned_cert->pubkey_type);
/* === pack Signature === */
dump_signature(dbg, level+1, cert->signature);
}
#endif
gateway-1.4.3/wap/wtp_pdu.h 0000644 0001750 0001750 00000010260 11132672003 014632 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wtp_pdu.h - definitions for unpacked WTP protocol data units
*
* This file generates a structure definition and some function
* declarations from wtp_pdu.def, using preprocessor magic.
*
* Richard Braakman
*/
#ifndef WTP_PDU_H
#define WTP_PDU_H
#include "gwlib/gwlib.h"
struct wtp_tpi {
int type;
Octstr *data;
};
typedef struct wtp_tpi WTP_TPI;
/* Enumerate the symbolic names of the PDUs */
enum wtp_pdu_types {
#define PDU(name, docstring, fields, is_valid) name,
#include "wtp_pdu.def"
#undef PDU
};
struct wtp_pdu {
int type;
List *options; /* List of WTP_TPI */
union {
/* For each PDU, declare a structure with its fields, named after the PDU */
#define PDU(name, docstring, fields, is_valid) struct name { fields } name;
#define UINT(field, docstring, bits) unsigned long field;
#define UINTVAR(field, docstring) unsigned long field;
#define OCTSTR(field, docstring, lengthfield) Octstr *field;
#define REST(field, docstring) Octstr *field;
#define TYPE(bits, value)
#define RESERVED(bits)
#define TPI(confield)
#include "wtp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
} u;
};
typedef struct wtp_pdu WTP_PDU;
void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data);
WTP_PDU *wtp_pdu_create(int type);
WTP_PDU *wtp_pdu_unpack(Octstr *data);
Octstr *wtp_pdu_pack(WTP_PDU *pdu);
void wtp_pdu_dump(WTP_PDU *pdu, int level);
void wtp_pdu_destroy(WTP_PDU *pdu);
void wtp_tpi_destroy(WTP_TPI *tpi);
#endif
gateway-1.4.3/wap/wtls_statesupport.c 0000644 0001750 0001750 00000076441 11132672002 017005 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtls_statesupport.c
*
* 2001 Nick Clarey, Yann Muller for 3G LAB
*/
#include "gwlib/gwlib.h"
#if (HAVE_WTLS_OPENSSL)
#include
#ifndef NO_RC5
#include
#else
#error "your OpenSSL installation lacks RC5 algorithm support"
#endif
#include "wtls_statesupport.h"
#define BLOCKLENGTH 64
#define INNERPAD 0x36
#define OUTERPAD 0x5C
extern X509* x509_cert;
extern RSA* private_key;
extern KeyExchangeSuite client_key_exchange_algo;
extern PublicKeyAlgorithm public_key_algo;
extern SignatureAlgorithm signature_algo;
Octstr* wtls_hmac_hash(Octstr* key, Octstr* data, WTLSMachine* wtls_machine);
Octstr* wtls_hash(Octstr* inputData, WTLSMachine* wtls_machine);
Octstr* wtls_encrypt_rc5(Octstr* data, WTLSMachine* wtls_machine);
Octstr* wtls_decrypt_rc5(Octstr* encryptedData, WTLSMachine* wtls_machine);
/* Add here the supported KeyExchangeSuites
used by wtls_choose_clientkeyid */
KeyExchangeSuite supportedKeyExSuite[] = { rsa_anon };
Octstr* wtls_decrypt(Octstr* buffer, WTLSMachine* wtls_machine)
{
return wtls_decrypt_rc5(buffer,wtls_machine);
}
/* This function will convert our buffer into a completed GenericBlockCipher */
Octstr* wtls_encrypt(Octstr* buffer, WTLSMachine* wtls_machine, int recordType)
{
Octstr* bufferCopy;
Octstr* encryptedContent;
Octstr* contentMac;
Octstr* padding;
Octstr* tempData;
unsigned char* tempPadding;
int paddingLength, contentLength, macSize, blockLength,
sequenceNumber, bufferLength;
int i;
/* Copy our buffer */
bufferCopy = octstr_duplicate(buffer);
/* Get the MAC of the content */
sequenceNumber = wtls_machine->server_seq_num;
bufferLength = octstr_len(buffer);
/* Copy the buffer in preparation for MAC calculation */
tempData = octstr_create("");
pack_int16(tempData, 0, sequenceNumber);
octstr_append_char(tempData, recordType);
pack_int16(tempData, octstr_len(tempData), bufferLength);
octstr_append(tempData, buffer);
/* Calculate the MAC */
contentMac = wtls_hmac_hash(wtls_machine->server_write_MAC_secret, tempData ,wtls_machine);
/* Calculate the padding length */
contentLength = octstr_len(bufferCopy);
macSize = hash_table[wtls_machine->mac_algorithm].mac_size;
blockLength = bulk_table[wtls_machine->bulk_cipher_algorithm].block_size;
paddingLength = (contentLength + macSize + 1) % (blockLength);
/* Append the MAC to the bufferCopy */
octstr_append(bufferCopy,contentMac);
if (paddingLength > 0) {
/* Pad with the paddingLength itself paddingLength times. Confused yet? */
tempPadding = gw_malloc(paddingLength);
for (i=0;i < paddingLength; i++) {
/* You're probably really spaced out around now...
see section 9.2.3.3 for more details... */
tempPadding[i] = paddingLength;
}
octstr_append_data(bufferCopy, tempPadding, paddingLength);
}
/* Add the length byte */
octstr_append_char(bufferCopy, paddingLength);
/* Encrypt the content */
encryptedContent = wtls_encrypt_rc5(bufferCopy,wtls_machine);
return encryptedContent;
}
/* P_hash as described in WAP WTLS section 11.3.2 */
Octstr* wtls_P_hash(Octstr* secret, Octstr* seed, int byteLength, WTLSMachine* wtls_machine)
{
Octstr *a;
Octstr *aPrev;
Octstr *aPlusSeed;
Octstr *hashTemp;
Octstr *hashedData;
hashedData = octstr_create("");
/* start with A(1) = HMAC_hash(secret, seed) */
aPrev = octstr_duplicate(seed);
do {
/* A(i) */
a = wtls_hmac_hash(secret, aPrev, wtls_machine);
aPlusSeed = octstr_cat(a, seed);
/* HMAC */
hashTemp = wtls_hmac_hash(secret, aPlusSeed, wtls_machine);
octstr_append(hashedData, hashTemp);
octstr_destroy(hashTemp);
/* Update a(i-1) */
octstr_destroy(aPrev);
aPrev = a;
} while(octstr_len(hashedData) < byteLength);
gw_free(aPlusSeed);
return hashedData;
}
/* Pseudo Random Function (PRF) as described in WAP WTLS section 11.3.2 */
Octstr* wtls_calculate_prf(Octstr* secret, Octstr* label,
Octstr* seed, int byteLength, WTLSMachine* wtls_machine)
{
Octstr* returnOctstr;
Octstr *labelPlusSeed;
/* Create label + seed */
labelPlusSeed = octstr_cat(label, seed);
/* PRF(secret, label, seed) = P_hash(secret, label + seed) */
returnOctstr = wtls_P_hash(secret, labelPlusSeed, byteLength, wtls_machine);
/* Return the first nbytes of the hashed data */
octstr_truncate(returnOctstr, byteLength);
gw_free(labelPlusSeed);
return returnOctstr;
}
/* MAC calculation */
Octstr* wtls_hmac_hash(Octstr* key, Octstr* data, WTLSMachine* wtls_machine)
{
static unsigned char final_mac[1024];
unsigned char *mac, *buffer, *keyString;
int mac_len, bufferlen, keylen;
Octstr *returnOctstr;
buffer = octstr_get_cstr(data);
bufferlen = octstr_len(data);
keyString = octstr_get_cstr(key);
keylen = octstr_len(key);
mac = final_mac;
switch (wtls_machine->mac_algorithm) {
case SHA_0:
/* no keyed MAC is calculated */
/* So what do we return ? */
break;
case SHA_40:
case SHA_80:
case SHA_NOLIMIT:
HMAC(EVP_sha1(), keyString, keylen,
buffer, bufferlen,
mac, &mac_len);
break;
case SHA_XOR_40:
// dunno yet
break;
case MD5_40:
case MD5_80:
case MD5_NOLIMIT:
HMAC(EVP_md5(), keyString, keylen,
buffer, bufferlen,
mac, &mac_len);
break;
}
returnOctstr = octstr_create_from_data(mac, mac_len);
}
/* Not to be confused with octstr_hash, this applies the currently set hashing
algorithm from wtls_machine to the supplied input data, returning a hashed
Octstr. If it fails, it will return a NULL pointer */
Octstr* wtls_hash(Octstr* inputData, WTLSMachine* wtls_machine)
{
int inputDataLength;
int outputDataLength;
unsigned char* outputDataTemp;
unsigned char* inputDataTemp;
unsigned char* tempPointer;
Octstr* outputData;
inputDataLength = octstr_len(inputData);
outputDataLength = hash_table[wtls_machine->mac_algorithm].key_size;
inputDataTemp = gw_malloc(inputDataLength);
outputDataTemp = gw_malloc(outputDataLength);
/* Copy the contents of inputData into inputDataTemp, ready for hashing */
tempPointer = octstr_get_cstr(inputData);
memcpy((void*) inputDataTemp, (void*)tempPointer, inputDataLength);
/* Hash away! */
// Here's where we need to hash on the selected algorithm, not just the SHA-1 algorithm
//debug("wtls", 0, "mac algo %d", wtls_machine->mac_algorithm);
switch (wtls_machine->mac_algorithm) {
case SHA_0:
/* no keyed MAC is calculated */
// So what do we return ?
break;
case SHA_40:
case SHA_80:
case SHA_NOLIMIT:
tempPointer = SHA1(inputDataTemp, inputDataLength, outputDataTemp);
break;
case SHA_XOR_40:
// dunno yet
break;
case MD5_40:
case MD5_80:
case MD5_NOLIMIT:
tempPointer = MD5(inputDataTemp, inputDataLength, outputDataTemp);
break;
}
if (tempPointer == NULL){
/* Pop out an error */
}
/* Get our output data setup */
outputData = octstr_create_from_data(outputDataTemp,outputDataLength);
/* some algorithms don't use the full length of H */
octstr_truncate(outputData, hash_table[wtls_machine->mac_algorithm].mac_size);
/* Delete our allocated memory */
gw_free(outputDataTemp);
gw_free(inputDataTemp);
outputDataTemp = NULL;
inputDataTemp = NULL;
/* Return the outputData */
return outputData;
}
Octstr* wtls_decrypt_rc5(Octstr* data, WTLSMachine* wtls_machine)
{
Octstr* encryptedData;
Octstr* decryptedData;
Octstr* duplicatedIv;
unsigned char* output;
unsigned char* input;
unsigned char* iv;
unsigned char* keyData;
int keyLen;
int ivLen;
int dataLen;
RC5_32_KEY* key = NULL;
ivLen = bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size;
duplicatedIv = octstr_duplicate(wtls_machine->client_write_IV);
iv = octstr_get_cstr(duplicatedIv);
keyLen = bulk_table[wtls_machine->bulk_cipher_algorithm].key_material;
keyData = octstr_get_cstr(wtls_machine->client_write_enc_key);
dataLen = octstr_len(data);
input = octstr_get_cstr(data);
key = gw_malloc (sizeof(RC5_32_KEY));
/* Key generation */
RC5_32_set_key(key, keyLen, keyData, RC5_16_ROUNDS);
/* Malloc our output */
output = gw_malloc (dataLen);
/* Encrypt the string */
debug("wtls_statesupport",0,"About to decrypt: dataLen = %d, iv = %x", dataLen, iv);
octstr_dump(data,0);
RC5_32_cbc_encrypt(input, output, dataLen, key, iv, RC5_DECRYPT);
debug("wtls_statesupport",0,"Decrypted");
decryptedData = octstr_create_from_data(output, dataLen);
octstr_dump(decryptedData,0);
/* Encrypt it just to test */
gw_free(output);
output = NULL;
output = gw_malloc (dataLen);
/* Ensure that we preserve the iv */
octstr_destroy(duplicatedIv);
duplicatedIv = octstr_duplicate(wtls_machine->client_write_IV);
iv = octstr_get_cstr(duplicatedIv);
octstr_get_many_chars(iv, wtls_machine->client_write_IV,0,ivLen);
input = octstr_get_cstr(decryptedData);
RC5_32_cbc_encrypt(input, output, dataLen, key, iv, RC5_ENCRYPT);
encryptedData = octstr_create_from_data(output, dataLen);
gw_free(output);
output = NULL;
octstr_destroy(duplicatedIv);
return decryptedData;
}
Octstr* wtls_encrypt_rc5(Octstr* data, WTLSMachine* wtls_machine)
{
Octstr* encryptedData;
Octstr* decryptedData;
Octstr* duplicatedIv;
unsigned char* output;
unsigned char* input;
unsigned char* iv;
unsigned char* keyData;
int keyLen;
int ivLen;
int dataLen;
RC5_32_KEY* key = NULL;
ivLen = bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size;
duplicatedIv = octstr_duplicate(wtls_machine->server_write_IV);
iv = octstr_get_cstr(duplicatedIv);
keyLen = bulk_table[wtls_machine->bulk_cipher_algorithm].key_material;
keyData = octstr_get_cstr(wtls_machine->server_write_enc_key);
dataLen = octstr_len(data);
input = octstr_get_cstr(data);
key = gw_malloc (sizeof(RC5_32_KEY));
/* Key generation */
debug("wtls_statesupport",0,"Key generation");
RC5_32_set_key(key, keyLen, keyData, RC5_16_ROUNDS);
/* Malloc our output */
output = gw_malloc (dataLen);
/* Encrypt the string */
RC5_32_cbc_encrypt(input, output, dataLen, key, iv, RC5_ENCRYPT);
encryptedData = octstr_create_from_data(output, dataLen);
/* Decrypt it just to test */
gw_free(output);
output = NULL;
output = gw_malloc (dataLen);
/* Ensure that we preserve the iv */
octstr_destroy(duplicatedIv);
duplicatedIv = octstr_duplicate(wtls_machine->server_write_IV);
iv = octstr_get_cstr(duplicatedIv);
octstr_get_many_chars(iv, wtls_machine->server_write_IV,0,ivLen);
input = octstr_get_cstr(encryptedData);
RC5_32_cbc_encrypt(input, output, dataLen, key, iv, RC5_DECRYPT);
decryptedData = octstr_create_from_data(output, dataLen);
gw_free(output);
output = NULL;
octstr_destroy(duplicatedIv);
return encryptedData;
}
Octstr* wtls_decrypt_rsa(Octstr* encryptedData)
{
int numBytesWritten=0,numBytesToRead=0;
Octstr *decryptedData=0;
unsigned char* tempDecryptionBuffer=0;
char* tempEncryptionPointer=0;
/* Allocate some memory for our decryption buffer */
tempDecryptionBuffer = gw_malloc(RSA_size(private_key));
/* Calculate the number of bytes to read from encryptedData when decrypting */
numBytesToRead = octstr_len(encryptedData);
/* Don't write to this pointer. Ever ever ever. */
tempEncryptionPointer = octstr_get_cstr(encryptedData);
/* Decrypt the data in encryptedData */
numBytesWritten = RSA_private_decrypt(numBytesToRead, tempEncryptionPointer,
tempDecryptionBuffer, private_key, RSA_PKCS1_PADDING);
if(numBytesWritten == -1) {
tempEncryptionPointer += 2;
numBytesToRead -= 2;
numBytesWritten = RSA_private_decrypt(numBytesToRead, tempEncryptionPointer,
tempDecryptionBuffer, private_key, RSA_PKCS1_PADDING);
}
/* Move the tempDecryptionBuffer to an Octstr */
decryptedData = octstr_create_from_data(tempDecryptionBuffer,numBytesWritten);
/* Deallocate the tempDecryptionBuffer */
gw_free(tempDecryptionBuffer);
tempDecryptionBuffer = NULL;
debug("wtls",0, "Decrypted secret");
octstr_dump( decryptedData, 0);
/* Return the decrypted data */
return decryptedData;
}
void wtls_decrypt_pdu_list(WTLSMachine *wtls_machine, List *pdu_list)
{
int i, listlen;
Octstr* decryptedData = NULL;
wtls_Payload *payload;
listlen = gwlist_len(pdu_list);
for( i=0; icipher) {
debug("wtls", 0, "Decrypting PDU %d", i);
decryptedData = wtls_decrypt(payload->data, wtls_machine);
/* replace the data */
octstr_destroy(payload->data);
payload->data = decryptedData;
}
else {
debug("wtls", 0, "PDU %d is not encrypted.", i);
}
}
}
RSAPublicKey* wtls_get_rsapublickey(void)
{
RSA* rsaStructure=0;
EVP_PKEY* publicKey=0;
BIGNUM *modulus=0,*exponent=0;
unsigned char* tempModulusStorage=0,*tempExponentStorage=0;
int numbytes=0;
RSAPublicKey* returnStructure=0;
Octstr *octstrModulus=0, *octstrExponent=0;
/* First, we need to extract the RSA structure from the X509 Cert */
/* Get the EVP_PKEY structure from the X509 cert */
publicKey = X509_PUBKEY_get(x509_cert->cert_info->key);
/* Take said EVP_PKEY structure and get the RSA component */
if (EVP_PKEY_type(publicKey->type) != EVP_PKEY_RSA)
{
return NULL;
}
else
{
rsaStructure = publicKey->pkey.rsa;
}
/* Then we need to grab the exponent component from the cert */
exponent = rsaStructure->e;
/* We need to allocate sufficient memory to hold the exponent */
numbytes = BN_num_bytes(exponent);
tempExponentStorage = gw_malloc(numbytes);
/* Then we get the exponent */
numbytes = BN_bn2bin(exponent, tempExponentStorage);
/* And finally we convert the exponent to an Octstr */
octstrExponent = octstr_create_from_data(tempExponentStorage,numbytes);
/* Then we need to grab the modulus component from the cert */
modulus = rsaStructure->n;
/* We need to allocate sufficient memory to hold the modulus */
numbytes = BN_num_bytes(modulus);
tempModulusStorage = gw_malloc(numbytes);
/* Then we get the modulus */
numbytes = BN_bn2bin(modulus, tempModulusStorage);
/* And finally we convert the modulus to an Octstr */
octstrModulus = octstr_create_from_data(tempModulusStorage,numbytes);
/* Put the components into our return structure */
returnStructure = gw_malloc(sizeof(RSAPublicKey));
returnStructure->rsa_exponent = octstrExponent;
returnStructure->rsa_modulus = octstrModulus;
/* And deallocate the memory allocated for holding the modulus */
gw_free(tempModulusStorage);
gw_free(tempExponentStorage);
tempModulusStorage = NULL;
tempExponentStorage = NULL;
return returnStructure;
}
Octstr* wtls_get_certificate(void)
{
unsigned char** pp;
unsigned char* ppStart;
int amountWritten = 1260;
Octstr* returnOctstr;
debug("wtls_get_certificate",0,"x509_cert : %x", x509_cert);
/* Convert the x509 certificate to DER-encoding */
amountWritten =i2d_X509(x509_cert, NULL);
debug("wtls_get_certificate",0,"amountWritten : %d", amountWritten);
/* Allocate some memory for *pp */
pp = (unsigned char**) gw_malloc(sizeof(unsigned char**));
/* Allocate the memory and call the same function again?!!?
What an original idea :-/ */
ppStart = (unsigned char *) gw_malloc (sizeof(unsigned char)*amountWritten);
debug("wtls_get_certificate",0,"x509_cert_DER_pre : %x", *pp);
*pp = ppStart;
amountWritten =i2d_X509(x509_cert, pp);
/* And we do this, because otherwise *pp is pointing to the end of the buffer. Yay */
*pp = ppStart;
debug("wtls_get_certificate",0,"x509_cert_DER_post : %x", *pp);
/* Convert the DER-encoded char string to an octstr */
returnOctstr = octstr_create_from_data(*pp,amountWritten);
/* Destroy the memory allocated temporarily above */
gw_free(*pp);
*pp = NULL;
/* Destroy the memory allocated for pp as well */
gw_free(pp);
pp = NULL;
/* Return the octstr */
return returnOctstr;
}
/* Chooses a CipherSuite from the list provided by the client.
Returns NULL if none is acceptable. */
CipherSuite* wtls_choose_ciphersuite(List* ciphersuites) {
CipherSuite* returnSuite = NULL;
CipherSuite* currentCS = NULL;
int i = 0;
int listLen;
listLen = gwlist_len(ciphersuites);
//returnSuite = gw_malloc(sizeof(CipherSuite));
/* the first CS in the list */
do {
/* the next CS in the list */
currentCS = gwlist_get(ciphersuites, i);
/* Check if we support this BulkCipher */
if(currentCS->bulk_cipher_algo >= RC5_CBC_40 &&
currentCS->bulk_cipher_algo <= IDEA_CBC) {
/* Check if we support this MAC algsorithm */
if(currentCS->mac_algo >= SHA_0 &&
currentCS->mac_algo <= MD5_NOLIMIT) {
/* We can use this CipherSuite then */
returnSuite = currentCS;
}
}
i++;
} while(returnSuite == NULL && i < listLen);
return returnSuite;
}
int isSupportedKeyEx(int keyExId) {
int maxSupported;
int i;
int retCode = 0;
maxSupported = sizeof(supportedKeyExSuite) / sizeof(KeyExchangeSuite);
for(i = 0; ikey_exchange_suite)) {
returnKey = i+1;
}
i++;
} while(returnKey == 0 && i < listLen);
return returnKey;
}
int wtls_choose_snmode(int snmode)
{
return 2;
}
int wtls_choose_krefresh(int krefresh)
{
return 2;
}
Random* wtls_get_random(void)
{
Random* randomData;
randomData = gw_malloc(sizeof(Random));
randomData->gmt_unix_time = 0x0000;
/* Yeah, I know, it's not very random */
randomData->random_bytes = octstr_create("000000000000");
return randomData;
}
int clienthellos_are_identical (List* pdu_list, List* last_received_packet)
{
return 0;
}
int certifcateverifys_are_identical (List* pdu_list, List* last_received_packet)
{
return 0;
}
int certificates_are_identical (List* pdu_list, List* last_received_packet)
{
return 0;
}
int clientkeyexchanges_are_identical (List* pdu_list, List* last_received_packet)
{
return 0;
}
int changecipherspecs_are_identical (List* pdu_list, List* last_received_packet)
{
return 0;
}
int finisheds_are_indentical (List* pdu_list, List* last_received_packet)
{
return 0;
}
int packet_contains_changecipherspec (List* pdu_list)
{
return 0;
}
int packet_contains_finished (List* pdu_list)
{
return 0;
}
int packet_contains_optional_stuff (List* pdu_list)
{
return 0;
}
int packet_contains_userdata (List* pdu_list)
{
/* FIXME: need to check if it is really Userdata !! */
return 1;
}
int packet_contains_clienthello (List* pdu_list)
{
return 0;
}
int is_critical_alert (List* pdu_list)
{
return 0;
}
int is_warning_alert (List* pdu_list)
{
return 0;
}
/* go through the list of wtls_Payloads and add the data of any
handshake message to wtls_machine->handshake_data */
void add_all_handshake_data(WTLSMachine *wtls_machine, List *pdu_list)
{
long i, listlen;
wtls_Payload *payload;
gw_assert(pdu_list != NULL);
listlen = gwlist_len(pdu_list);
debug("wtls", 0,"adding handshake data from %d PDU(s)", listlen);
for(i=0; itype == Handshake_PDU) {
octstr_insert(wtls_machine->handshake_data, payload->data,
octstr_len(wtls_machine->handshake_data));
debug("wtls", 0, "Data from PDU %d:", i);
octstr_dump(payload->data, 2);
}
}
}
void calculate_server_key_block(WTLSMachine *wtls_machine)
{
Octstr* concatenatedRandoms=0;
Octstr* labelMaster=0;
Octstr* key_block;
Octstr* final_server_write_enc_key = NULL;
Octstr* final_server_write_IV = NULL;
Octstr* emptySecret = NULL;
/* Concatenate our random data */
concatenatedRandoms = octstr_create("");
pack_int16(concatenatedRandoms, 0, wtls_machine->server_seq_num);
octstr_append(concatenatedRandoms, wtls_machine->server_random);
octstr_append(concatenatedRandoms, wtls_machine->client_random);
/* Calculate the key_block */
labelMaster = octstr_create("server expansion");
key_block = wtls_calculate_prf(wtls_machine->master_secret, labelMaster,
concatenatedRandoms,
hash_table[wtls_machine->mac_algorithm].key_size
+ bulk_table[wtls_machine->bulk_cipher_algorithm].key_material
+ bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size,
wtls_machine );
octstr_destroy(labelMaster);
labelMaster = NULL;
octstr_destroy(concatenatedRandoms);
concatenatedRandoms = NULL;
/* Break the key_block in its 3 parts */
wtls_machine->server_write_MAC_secret = octstr_copy(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size);
octstr_delete(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size);
wtls_machine->server_write_enc_key = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material);
octstr_delete(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material);
wtls_machine->server_write_IV = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size);
/* Additional calculations for exportable encryption algos */
if(bulk_table[wtls_machine->bulk_cipher_algorithm].is_exportable == EXPORTABLE) {
concatenatedRandoms = octstr_cat(wtls_machine->client_random, wtls_machine->server_random);
labelMaster = octstr_create("server write key");
final_server_write_enc_key = wtls_calculate_prf(wtls_machine->server_write_enc_key, labelMaster,
concatenatedRandoms,
bulk_table[wtls_machine->bulk_cipher_algorithm].key_material,
wtls_machine);
octstr_destroy(labelMaster);
labelMaster = NULL;
octstr_destroy(concatenatedRandoms);
concatenatedRandoms = NULL;
octstr_destroy(wtls_machine->server_write_enc_key);
wtls_machine->server_write_enc_key = final_server_write_enc_key;
final_server_write_enc_key = NULL;
concatenatedRandoms = octstr_create("");
octstr_append_char(concatenatedRandoms, wtls_machine->server_seq_num);
octstr_append(concatenatedRandoms, wtls_machine->client_random);
octstr_append(concatenatedRandoms, wtls_machine->server_random);
emptySecret = octstr_create("");
final_server_write_IV = wtls_calculate_prf(emptySecret, labelMaster,
concatenatedRandoms,
bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size,
wtls_machine);
octstr_destroy(labelMaster);
labelMaster = NULL;
octstr_destroy(concatenatedRandoms);
concatenatedRandoms = NULL;
}
}
void calculate_client_key_block(WTLSMachine *wtls_machine) {
Octstr* concatenatedRandoms=0;
Octstr* key_block;
Octstr* final_client_write_enc_key = NULL;
Octstr* final_client_write_IV = NULL;
Octstr* emptySecret = NULL;
Octstr* labelMaster=0;
/* Concatenate our random data */
concatenatedRandoms = octstr_create("");
pack_int16(concatenatedRandoms, 0,wtls_machine->client_seq_num);
octstr_append(concatenatedRandoms, wtls_machine->server_random);
octstr_append(concatenatedRandoms, wtls_machine->client_random);
/* Calculate the key_block */
labelMaster = octstr_create("client expansion");
key_block = wtls_calculate_prf(wtls_machine->master_secret, labelMaster,
concatenatedRandoms,
hash_table[wtls_machine->mac_algorithm].key_size
+ bulk_table[wtls_machine->bulk_cipher_algorithm].key_material
+ bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size,
wtls_machine );
octstr_destroy(labelMaster);
labelMaster = NULL;
octstr_destroy(concatenatedRandoms);
concatenatedRandoms = NULL;
/* Break the key_block in its 3 parts */
wtls_machine->client_write_MAC_secret = octstr_copy(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size);
octstr_delete(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size);
wtls_machine->client_write_enc_key = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material);
octstr_delete(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material);
wtls_machine->client_write_IV = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size);
/* Additional calculations for exportable encryption algos */
if(bulk_table[wtls_machine->bulk_cipher_algorithm].is_exportable == EXPORTABLE) {
concatenatedRandoms = octstr_cat(wtls_machine->client_random, wtls_machine->server_random);
labelMaster = octstr_create("client write key");
final_client_write_enc_key = wtls_calculate_prf(wtls_machine->client_write_enc_key, labelMaster,
concatenatedRandoms,
bulk_table[wtls_machine->bulk_cipher_algorithm].key_material,
wtls_machine);
octstr_destroy(labelMaster);
labelMaster = NULL;
octstr_destroy(wtls_machine->client_write_enc_key);
wtls_machine->client_write_enc_key = final_client_write_enc_key;
final_client_write_enc_key = NULL;
octstr_destroy(labelMaster);
labelMaster = NULL;
octstr_destroy(concatenatedRandoms);
concatenatedRandoms = NULL;
emptySecret = octstr_create("");
final_client_write_IV = wtls_calculate_prf(emptySecret, labelMaster,
concatenatedRandoms,
bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size,
wtls_machine);
octstr_destroy(labelMaster);
labelMaster = NULL;
octstr_destroy(concatenatedRandoms);
concatenatedRandoms = NULL;
}
}
#endif
gateway-1.4.3/wap/wsp_headers.h 0000644 0001750 0001750 00000016246 11132672003 015466 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_headers.h - WSP PDU headers implementation header
*
* Kalle Marjola
*/
#ifndef WSP_HEADERS_H
#define WSP_HEADERS_H
#include "gwlib/gwlib.h"
#define WSP_FIELD_VALUE_NUL_STRING 1
#define WSP_FIELD_VALUE_ENCODED 2
#define WSP_FIELD_VALUE_DATA 3
#define WSP_FIELD_VALUE_NONE 4 /* secondary_field_value only */
/* The value defined as Quote in 8.4.2.1 */
#define WSP_QUOTE 127
/* Largest value that will fit in a Short-integer encoding */
#define MAX_SHORT_INTEGER 127
/* Marker values used in the encoding */
#define BASIC_AUTHENTICATION 128
#define ABSOLUTE_TIME 128
#define RELATIVE_TIME 129
#define BYTE_RANGE 128
#define SUFFIX_BYTE_RANGE 129
/* Use this value for Expires headers if we can't parse the expiration
* date. It's about one day after the start of the epoch. We don't
* use the exact start of the epoch because some clients have trouble
* with that. */
#define LONG_AGO_VALUE 100000
/* LIST is a comma-separated list such as is described in the "#rule"
* entry of RFC2616 section 2.1. */
#define LIST 1
/* BROKEN_LIST is a list of "challenge" or "credentials" elements
* such as described in RFC2617. I call it broken because the
* parameters are separated with commas, instead of with semicolons
* like everywhere else in HTTP. Parsing is more difficult because
* commas are also used to separate list elements. */
#define BROKEN_LIST 2
#define TABLE_SIZE(table) ((long)(sizeof(table) / sizeof(table[0])))
struct parameter
{
Octstr *key;
Octstr *value;
};
typedef struct parameter Parameter;
typedef int header_pack_func_t(Octstr *packed, Octstr *value);
struct headerinfo
{
/* The WSP_HEADER_* enumeration value for this header */
int header;
header_pack_func_t *func;
/* True if this header type allows multiple elements per
* header on the HTTP side. */
int allows_list;
};
/* All WSP packing/unpacking routines that are exported for use within
* external modules, ie. MMS encoding/decoding.
*/
int wsp_field_value(ParseContext *context, int *well_known_value);
void wsp_skip_field_value(ParseContext *context);
int wsp_secondary_field_value(ParseContext *context, long *result);
void parm_destroy_item(void *parm);
List *wsp_strip_parameters(Octstr *value);
/* unpacking */
Octstr *wsp_unpack_integer_value(ParseContext *context);
Octstr *wsp_unpack_version_value(long value);
void wsp_unpack_all_parameters(ParseContext *context, Octstr *decoded);
Octstr *wsp_unpack_date_value(ParseContext *context);
void wsp_unpack_well_known_field(List *unpacked, int field_type,
ParseContext *context);
void wsp_unpack_app_header(List *unpacked, ParseContext *context);
/* packing */
void wsp_pack_integer_value(Octstr *packed, unsigned long integer);
int wsp_pack_date(Octstr *packet, Octstr *value);
int wsp_pack_retry_after(Octstr *packet, Octstr *value);
int wsp_pack_text(Octstr *packet, Octstr *value);
int wsp_pack_quoted_text(Octstr *packed, Octstr *text);
int wsp_pack_integer_string(Octstr *packet, Octstr *value);
int wsp_pack_version_value(Octstr *packet, Octstr *value);
int wsp_pack_constrained_value(Octstr *packed, Octstr *text, long value);
void wsp_pack_value(Octstr *packed, Octstr *encoded);
void wsp_pack_parameters(Octstr *packed, List *parms);
int wsp_pack_list(Octstr *packed, long fieldnum, List *elements, int i);
void wsp_pack_short_integer(Octstr *packed, unsigned long integer);
void wsp_pack_separate_content_type(Octstr *packed, List *headers);
Octstr *wsp_unpack_accept_general_form(ParseContext *context);
Octstr *wsp_unpack_accept_charset_general_form(ParseContext *context);
int wsp_pack_content_type(Octstr *packet, Octstr *value);
int wsp_pack_application_header(Octstr *packed,
Octstr *fieldname, Octstr *value);
void wsp_pack_long_integer(Octstr *packed, unsigned long integer);
/* Return an HTTPHeader linked list which must be freed by the caller
* (see http.h for details of HTTPHeaders). Cannot fail.
* The second argument is true if the headers will have a leading
* Content-Type field. Some WSP PDUs encode Content-Type separately
* this way for historical reasons.
*/
List *wsp_headers_unpack(Octstr *headers, int content_type);
/* Take a List of headers, encode them according to the WSP spec,
* and return the encoded headers as an Octstr.
* The second argument is true if the encoded headers should have
* a leading content-type field. See the note for wsp_headers_unpack. */
Octstr *wsp_headers_pack(List *headers, int separate_content_type, int wsp_version);
#endif
gateway-1.4.3/wap/wsp_server_method_machine.def 0000644 0001750 0001750 00000006150 11132672003 020705 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_server_method_machine.def - define a WSP method machine
*
* Lars Wirzenius
*/
#if !defined(INTEGER) || \
!defined(ADDRTUPLE) || \
!defined(EVENT) || \
!defined(MACHINE)
#error "Some required macro is missing."
#endif
MACHINE(
INTEGER(transaction_id)
INTEGER(state)
ADDRTUPLE(addr_tuple)
EVENT(invoke)
INTEGER(session_id)
)
#undef INTEGER
#undef ADDRTUPLE
#undef EVENT
#undef MACHINE
gateway-1.4.3/wap/wsp_session.c 0000644 0001750 0001750 00000125474 11132672002 015534 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_session.c - Implement WSP session oriented service
*
* Lars Wirzenius
* Stipe Tolj
*/
#include
#include
#include "gwlib/gwlib.h"
#include "wsp.h"
#include "wsp_pdu.h"
#include "wsp_headers.h"
#include "wsp_caps.h"
#include "wsp_strings.h"
#include "cookies.h"
#include "wap.h"
#include "wtp.h"
typedef enum {
#define STATE_NAME(name) name,
#define ROW(state, event, condition, action, next_state)
#include "wsp_server_session_states.def"
#define STATE_NAME(name) name,
#define ROW(state, event, condition, action, next_state)
#include "wsp_server_method_states.def"
#define STATE_NAME(name) name,
#define ROW(state, event, condition, action, next_state)
#include "wsp_server_push_states.def"
WSPState_count
} WSPState;
/*
* Give the status the module:
*
* limbo
* not running at all
* running
* operating normally
* terminating
* waiting for operations to terminate, returning to limbo
*/
static enum { limbo, running, terminating } run_status = limbo;
static wap_dispatch_func_t *dispatch_to_wtp_resp;
static wap_dispatch_func_t *dispatch_to_wtp_init;
static wap_dispatch_func_t *dispatch_to_appl;
static wap_dispatch_func_t *dispatch_to_ota;
/*
* True iff "Session resume facility" is enabled. This means we are
* willing to let sessions go to SUSPENDED state, and later resume them.
* Currently we always support it, but this may become configurable
* at some point.
*/
static int resume_enabled = 1;
static List *queue = NULL;
static List *session_machines = NULL;
static Counter *session_id_counter = NULL;
static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu);
static void handle_session_event(WSPMachine *machine, WAPEvent *event,
WSP_PDU *pdu);
static WSPMachine *machine_create(void);
static void machine_destroy(void *p);
static void handle_method_event(WSPMachine *session, WSPMethodMachine *machine, WAPEvent *event, WSP_PDU *pdu);
static void cant_handle_event(WSPMachine *sm, WAPEvent *event);
static WSPMethodMachine *method_machine_create(WSPMachine *, long);
static void method_machine_destroy(void *msm);
static void handle_push_event(WSPMachine *session, WSPPushMachine *machine,
WAPEvent *e);
static WSPPushMachine *push_machine_create(WSPMachine *session, long id);
static void push_machine_destroy(void *p);
static char *state_name(WSPState state);
static unsigned long next_wsp_session_id(void);
static List *make_capabilities_reply(WSPMachine *m);
static List *make_reply_headers(WSPMachine *m);
static Octstr *make_connectreply_pdu(WSPMachine *m);
static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers);
static WSP_PDU *make_confirmedpush_pdu(WAPEvent *e);
static WSP_PDU *make_push_pdu(WAPEvent *e);
static int transaction_belongs_to_session(void *session, void *tuple);
static int find_by_session_id(void *session, void *idp);
static int same_client(void *sm1, void *sm2);
static WSPMethodMachine *find_method_machine(WSPMachine *, long id);
static WSPPushMachine *find_push_machine(WSPMachine *m, long id);
static List *unpack_new_headers(WSPMachine *sm, Octstr *hdrs);
static void disconnect_other_sessions(WSPMachine *sm);
static void send_abort(long reason, long handle);
static void indicate_disconnect(WSPMachine *sm, long reason);
static void indicate_suspend(WSPMachine *sm, long reason);
static void indicate_resume(WSPMachine *sm, WAPAddrTuple *tuple,
List *client_headers);
static void release_holding_methods(WSPMachine *sm);
static void abort_methods(WSPMachine *sm, long reason);
static void abort_pushes(WSPMachine *sm, long reason);
static void method_abort(WSPMethodMachine *msm, long reason);
static void indicate_method_abort(WSPMethodMachine *msm, long reason);
static WAPEvent *make_abort(long reason, long handle);
static void send_invoke(WSPMachine *session, WSP_PDU *pdu, WAPEvent *e,
long class);
static void send_abort_to_initiator(long reason, long handle);
static void indicate_pushabort(WSPPushMachine *machine, long reason);
static void confirm_push(WSPPushMachine *machine);
static void main_thread(void *);
static int id_belongs_to_session (void *, void *);
static int wsp_encoding_string_to_version(Octstr *enc);
static Octstr *wsp_encoding_version_to_string(int version);
/***********************************************************************
* Public functions.
*/
void wsp_session_init(wap_dispatch_func_t *responder_dispatch,
wap_dispatch_func_t *initiator_dispatch,
wap_dispatch_func_t *application_dispatch,
wap_dispatch_func_t *push_ota_dispatch) {
queue = gwlist_create();
gwlist_add_producer(queue);
session_machines = gwlist_create();
session_id_counter = counter_create();
dispatch_to_wtp_resp = responder_dispatch;
dispatch_to_wtp_init = initiator_dispatch;
dispatch_to_appl = application_dispatch;
dispatch_to_ota = push_ota_dispatch;
wsp_strings_init();
run_status = running;
gwthread_create(main_thread, NULL);
}
void wsp_session_shutdown(void) {
gw_assert(run_status == running);
run_status = terminating;
gwlist_remove_producer(queue);
gwthread_join_every(main_thread);
gwlist_destroy(queue, wap_event_destroy_item);
debug("wap.wsp", 0, "WSP: %ld session machines left.",
gwlist_len(session_machines));
gwlist_destroy(session_machines, machine_destroy);
counter_destroy(session_id_counter);
wsp_strings_shutdown();
}
void wsp_session_dispatch_event(WAPEvent *event) {
wap_event_assert(event);
gwlist_produce(queue, event);
}
/***********************************************************************
* Local functions
*/
static void main_thread(void *arg) {
WAPEvent *e;
WSPMachine *sm;
WSP_PDU *pdu;
while (run_status == running && (e = gwlist_consume(queue)) != NULL) {
wap_event_assert(e);
switch (e->type) {
case TR_Invoke_Ind:
pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data);
if (pdu == NULL) {
warning(0, "WSP: Broken PDU ignored.");
wap_event_destroy(e);
continue;
}
break;
default:
pdu = NULL;
break;
}
sm = find_session_machine(e, pdu);
if (sm == NULL) {
wap_event_destroy(e);
} else {
handle_session_event(sm, e, pdu);
}
wsp_pdu_destroy(pdu);
}
}
static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu) {
WSPMachine *sm;
long session_id;
WAPAddrTuple *tuple;
tuple = NULL;
session_id = -1;
switch (event->type) {
case TR_Invoke_Ind:
tuple = wap_addr_tuple_duplicate(
event->u.TR_Invoke_Ind.addr_tuple);
break;
case TR_Invoke_Cnf:
tuple = wap_addr_tuple_duplicate(
event->u.TR_Invoke_Cnf.addr_tuple);
break;
case TR_Result_Cnf:
tuple = wap_addr_tuple_duplicate(
event->u.TR_Result_Cnf.addr_tuple);
break;
case TR_Abort_Ind:
tuple = wap_addr_tuple_duplicate(
event->u.TR_Abort_Ind.addr_tuple);
break;
case S_Connect_Res:
session_id = event->u.S_Connect_Res.session_id;
break;
case S_Resume_Res:
session_id = event->u.S_Resume_Res.session_id;
break;
case Disconnect_Event:
session_id = event->u.Disconnect_Event.session_handle;
break;
case Suspend_Event:
session_id = event->u.Suspend_Event.session_handle;
break;
case S_MethodInvoke_Res:
session_id = event->u.S_MethodInvoke_Res.session_id;
break;
case S_MethodResult_Req:
session_id = event->u.S_MethodResult_Req.session_id;
break;
case S_ConfirmedPush_Req:
session_id = event->u.S_ConfirmedPush_Req.session_id;
break;
case S_Push_Req:
session_id = event->u.S_Push_Req.session_id;
break;
default:
error(0, "WSP: Cannot find machine for %s event",
wap_event_name(event->type));
}
gw_assert(tuple != NULL || session_id != -1);
/* Pre-state-machine tests, according to 7.1.5. After the tests,
* caller will pass the event to sm if sm is not NULL. */
sm = NULL;
/* First test is for MRUEXCEEDED, and we don't have a MRU */
/* Second test is for class 2 TR-Invoke.ind with Connect PDU */
if (event->type == TR_Invoke_Ind &&
event->u.TR_Invoke_Ind.tcl == 2 &&
pdu->type == Connect) {
/* Create a new session, even if there is already
* a session open for this address. The new session
* will take care of killing the old ones. */
sm = machine_create();
gw_assert(tuple != NULL);
sm->addr_tuple = wap_addr_tuple_duplicate(tuple);
sm->connect_handle = event->u.TR_Invoke_Ind.handle;
/* Third test is for class 2 TR-Invoke.ind with Resume PDU */
} else if (event->type == TR_Invoke_Ind &&
event->u.TR_Invoke_Ind.tcl == 2 &&
pdu->type == Resume) {
/* Pass to session identified by session id, not
* the address tuple. */
session_id = pdu->u.Resume.sessionid;
sm = gwlist_search(session_machines, &session_id,
find_by_session_id);
if (sm == NULL) {
/* No session; TR-Abort.req(DISCONNECT) */
send_abort(WSP_ABORT_DISCONNECT,
event->u.TR_Invoke_Ind.handle);
}
/* Fourth test is for a class 1 or 2 TR-Invoke.Ind with no
* session for that address tuple. We also handle class 0
* TR-Invoke.ind here by ignoring them; this seems to be
* an omission in the spec table. */
} else if (event->type == TR_Invoke_Ind) {
sm = gwlist_search(session_machines, tuple,
transaction_belongs_to_session);
if (sm == NULL && (event->u.TR_Invoke_Ind.tcl == 1 ||
event->u.TR_Invoke_Ind.tcl == 2)) {
send_abort(WSP_ABORT_DISCONNECT,
event->u.TR_Invoke_Ind.handle);
}
/* Other tests are for events not handled by the state tables;
* do those later, after we've tried to handle them. */
} else {
if (session_id != -1) {
sm = gwlist_search(session_machines, &session_id,
find_by_session_id);
} else {
sm = gwlist_search(session_machines, tuple,
transaction_belongs_to_session);
}
/* The table doesn't really say what we should do with
* non-Invoke events for which there is no session. But
* such a situation means there is an error _somewhere_
* in the gateway. */
if (sm == NULL) {
error(0, "WSP: Cannot find session machine for event.");
wap_event_dump(event);
}
}
wap_addr_tuple_destroy(tuple);
return sm;
}
static void handle_session_event(WSPMachine *sm, WAPEvent *current_event,
WSP_PDU *pdu) {
debug("wap.wsp", 0, "WSP: machine %p, state %s, event %s",
(void *) sm,
state_name(sm->state),
wap_event_name(current_event->type));
#define STATE_NAME(name)
#define ROW(state_name, event, condition, action, next_state) \
{ \
struct event *e; \
e = ¤t_event->u.event; \
if (sm->state == state_name && \
current_event->type == event && \
(condition)) { \
action \
sm->state = next_state; \
debug("wap.wsp", 0, "WSP %ld: New state %s", \
sm->session_id, #next_state); \
goto end; \
} \
}
#include "wsp_server_session_states.def"
cant_handle_event(sm, current_event);
end:
wap_event_destroy(current_event);
if (sm->state == NULL_SESSION)
machine_destroy(sm);
}
static void cant_handle_event(WSPMachine *sm, WAPEvent *event) {
/* We do the rest of the pre-state-machine tests here. The first
* four were done in find_session_machine(). The fifth is a
* class 1 or 2 TR-Invoke.ind not handled by the state tables. */
if (event->type == TR_Invoke_Ind &&
(event->u.TR_Invoke_Ind.tcl == 1 ||
event->u.TR_Invoke_Ind.tcl == 2)) {
warning(0, "WSP: Can't handle TR-Invoke.ind, aborting transaction.");
debug("wap.wsp", 0, "WSP: The unhandled event:");
wap_event_dump(event);
send_abort(WSP_ABORT_PROTOERR,
event->u.TR_Invoke_Ind.handle);
/* The sixth is a class 0 TR-Invoke.ind not handled by state tables. */
} else if (event->type == TR_Invoke_Ind) {
warning(0, "WSP: Can't handle TR-Invoke.ind, ignoring.");
debug("wap.wsp", 0, "WSP: The ignored event:");
wap_event_dump(event);
/* The seventh is any other event not handled by state tables. */
} else {
error(0, "WSP: Can't handle event. Aborting session.");
debug("wap.wsp", 0, "WSP: The unhandled event:");
wap_event_dump(event);
/* TR-Abort.req(PROTOERR) if it is some other transaction
* event than abort. */
/* Currently that means TR-Result.cnf, because we already
* tested for Invoke. */
/* FIXME We need a better way to get at event values than
* by hardcoding the types. */
if (event->type == TR_Result_Cnf) {
send_abort(WSP_ABORT_PROTOERR,
event->u.TR_Result_Cnf.handle);
}
/* Abort(PROTOERR) all method and push transactions */
abort_methods(sm, WSP_ABORT_PROTOERR);
abort_pushes(sm, WSP_ABORT_PROTOERR);
/* S-Disconnect.ind(PROTOERR) */
indicate_disconnect(sm, WSP_ABORT_PROTOERR);
}
}
static WSPMachine *machine_create(void) {
WSPMachine *p;
p = gw_malloc(sizeof(WSPMachine));
debug("wap.wsp", 0, "WSP: Created WSPMachine %p", (void *) p);
#define INTEGER(name) p->name = 0;
#define OCTSTR(name) p->name = NULL;
#define HTTPHEADERS(name) p->name = NULL;
#define ADDRTUPLE(name) p->name = NULL;
#define MACHINESLIST(name) p->name = gwlist_create();
#define CAPABILITIES(name) p->name = NULL;
#define COOKIES(name) p->name = gwlist_create();
#define REFERER(name) p->name = NULL;
#define MACHINE(fields) fields
#include "wsp_server_session_machine.def"
p->state = NULL_SESSION;
/* set capabilities to default values (defined in 1.1) */
p->client_SDU_size = 1400;
p->MOR_push = 1;
/* Insert new machine at the _front_, because 1) it's more likely
* to get events than old machines are, so this speeds up the linear
* search, and 2) we want the newest machine to get any method
* invokes that come through before the Connect is established. */
gwlist_insert(session_machines, 0, p);
return p;
}
static void destroy_methodmachines(List *machines) {
if (gwlist_len(machines) > 0) {
warning(0, "Destroying WSP session with %ld active methods\n",
gwlist_len(machines));
}
gwlist_destroy(machines, method_machine_destroy);
}
static void destroy_pushmachines(List *machines) {
if (gwlist_len(machines) > 0) {
warning(0, "Destroying WSP session with %ld active pushes\n",
gwlist_len(machines));
}
gwlist_destroy(machines, push_machine_destroy);
}
static void machine_destroy(void *pp) {
WSPMachine *p;
p = pp;
debug("wap.wsp", 0, "Destroying WSPMachine %p", pp);
gwlist_delete_equal(session_machines, p);
#define INTEGER(name) p->name = 0;
#define OCTSTR(name) octstr_destroy(p->name);
#define HTTPHEADERS(name) http_destroy_headers(p->name);
#define ADDRTUPLE(name) wap_addr_tuple_destroy(p->name);
#define MACHINESLIST(name) destroy_##name(p->name);
#define CAPABILITIES(name) wsp_cap_destroy_list(p->name);
#define COOKIES(name) cookies_destroy(p->name);
#define REFERER(name) octstr_destroy(p->name);
#define MACHINE(fields) fields
#include "wsp_server_session_machine.def"
gw_free(p);
}
struct msm_pattern {
WAPAddrTuple *addr_tuple;
long msmid, tid;
};
/* This function does NOT consume its event; it leaves that task up
* to the parent session */
static void handle_method_event(WSPMachine *sm, WSPMethodMachine *msm,
WAPEvent *current_event, WSP_PDU *pdu) {
if (msm == NULL) {
warning(0, "No method machine for event.");
wap_event_dump(current_event);
return;
}
debug("wap.wsp", 0, "WSP: method %ld, state %s, event %s",
msm->transaction_id, state_name(msm->state),
wap_event_name(current_event->type));
gw_assert(sm->session_id == msm->session_id);
#define STATE_NAME(name)
#define ROW(state_name, event, condition, action, next_state) \
{ \
struct event *e; \
e = ¤t_event->u.event; \
if (msm->state == state_name && \
current_event->type == event && \
(condition)) { \
action \
msm->state = next_state; \
debug("wap.wsp", 0, "WSP %ld/%ld: New method state %s", \
msm->session_id, msm->transaction_id, #next_state); \
goto end; \
} \
}
#include "wsp_server_method_states.def"
cant_handle_event(sm, current_event);
end:
if (msm->state == NULL_METHOD) {
method_machine_destroy(msm);
gwlist_delete_equal(sm->methodmachines, msm);
}
}
static WSPMethodMachine *method_machine_create(WSPMachine *sm,
long wtp_handle) {
WSPMethodMachine *msm;
msm = gw_malloc(sizeof(*msm));
#define INTEGER(name) msm->name = 0;
#define ADDRTUPLE(name) msm->name = NULL;
#define EVENT(name) msm->name = NULL;
#define MACHINE(fields) fields
#include "wsp_server_method_machine.def"
msm->transaction_id = wtp_handle;
msm->state = NULL_METHOD;
msm->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple);
msm->session_id = sm->session_id;
gwlist_append(sm->methodmachines, msm);
return msm;
}
static void method_machine_destroy(void *p) {
WSPMethodMachine *msm;
if (p == NULL)
return;
msm = p;
debug("wap.wsp", 0, "Destroying WSPMethodMachine %ld",
msm->transaction_id);
#define INTEGER(name)
#define ADDRTUPLE(name) wap_addr_tuple_destroy(msm->name);
#define EVENT(name) wap_event_destroy(msm->name);
#define MACHINE(fields) fields
#include "wsp_server_method_machine.def"
gw_free(msm);
}
static void handle_push_event(WSPMachine *sm, WSPPushMachine *pm,
WAPEvent *current_event)
{
if (pm == NULL) {
warning(0, "No push machine for event.");
wap_event_dump(current_event);
return;
}
debug("wap.wsp", 0, "WSP(tid/pid): push %ld/%ld, state %s, event %s",
pm->transaction_id, pm->server_push_id, state_name(pm->state),
wap_event_name(current_event->type));
gw_assert(sm->session_id == pm->session_id);
#define STATE_NAME(name)
#define ROW(state_name, event, condition, action, next_state) \
{ \
if (pm->state == state_name && \
current_event->type == event && \
(condition)) { \
action \
pm->state = next_state; \
debug("wap.wsp", 0, "WSP %ld/%ld: New push state %s", \
pm->session_id, pm->transaction_id, #next_state); \
goto end; \
} \
}
#include "wsp_server_push_states.def"
cant_handle_event(sm, current_event);
end:
if (pm->state == SERVER_PUSH_NULL_STATE) {
push_machine_destroy(pm);
gwlist_delete_equal(sm->pushmachines, pm);
}
}
static WSPPushMachine *push_machine_create(WSPMachine *sm,
long pid)
{
WSPPushMachine *m;
m = gw_malloc(sizeof(WSPPushMachine));
#define INTEGER(name) m->name = 0;
#define ADDRTUPLE(name) m->name = NULL;
#define HTTPHEADER(name) m->name = http_create_empty_headers();
#define MACHINE(fields) fields
#include "wsp_server_push_machine.def"
m->server_push_id = pid;
m->transaction_id = pid;
m->state = SERVER_PUSH_NULL_STATE;
m->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple);
m->session_id = sm->session_id;
gwlist_append(sm->pushmachines, m);
return m;
}
static void push_machine_destroy(void *p)
{
WSPPushMachine *m = NULL;
if (p == NULL)
return;
m = p;
debug("wap.wsp", 0, "Destroying WSPPushMachine %ld",
m->transaction_id);
#define INTEGER(name)
#define ADDRTUPLE(name) wap_addr_tuple_destroy(m->name);
#define HTTPHEADER(name) http_destroy_headers(m->name);
#define MACHINE(fields) fields
#include "wsp_server_push_machine.def"
gw_free(m);
}
static char *state_name(WSPState state) {
switch (state) {
#define STATE_NAME(name) case name: return #name;
#define ROW(state, event, cond, stmt, next_state)
#include "wsp_server_session_states.def"
#define STATE_NAME(name) case name: return #name;
#define ROW(state, event, cond, stmt, next_state)
#include "wsp_server_method_states.def"
#define STATE_NAME(name) case name: return #name;
#define ROW(state, event, cond, stmt, next_state)
#include "wsp_server_push_states.def"
default:
return "unknown wsp state";
}
}
static unsigned long next_wsp_session_id(void) {
return counter_increase(session_id_counter);
}
static void sanitize_capabilities(List *caps, WSPMachine *m) {
long i;
Capability *cap;
unsigned long ui;
for (i = 0; i < gwlist_len(caps); i++) {
cap = gwlist_get(caps, i);
/* We only know numbered capabilities. Let the application
* layer negotiate whatever it wants for unknown ones. */
if (cap->name != NULL)
continue;
switch (cap->id) {
case WSP_CAPS_CLIENT_SDU_SIZE:
/* Check if it's a valid uintvar. The value is the
* max SDU size we will send, and there's no
* internal limit to that, so accept any value. */
if (cap->data != NULL &&
octstr_extract_uintvar(cap->data, &ui, 0) < 0)
goto bad_cap;
else
m->client_SDU_size = ui;
break;
case WSP_CAPS_SERVER_SDU_SIZE:
/* Check if it's a valid uintvar */
if (cap->data != NULL &&
(octstr_extract_uintvar(cap->data, &ui, 0) < 0))
goto bad_cap;
/* XXX Our MRU is not quite unlimited, since we
* use signed longs in the library functions --
* should we make sure we limit the reply value
* to LONG_MAX? (That's already a 2GB packet) */
break;
case WSP_CAPS_PROTOCOL_OPTIONS:
/* Currently we don't support any Push, nor
* session resume, nor acknowledgement headers,
* so make sure those bits are not set. */
if (cap->data != NULL && octstr_len(cap->data) > 0
&& (octstr_get_char(cap->data, 0) & 0xf0) != 0) {
warning(0, "WSP: Application layer tried to "
"negotiate protocol options.");
octstr_set_bits(cap->data, 0, 4, 0);
}
break;
case WSP_CAPS_EXTENDED_METHODS:
/* XXX Check format here */
break;
case WSP_CAPS_HEADER_CODE_PAGES:
/* We don't support any yet, so don't let this
* be negotiated. */
if (cap->data)
goto bad_cap;
break;
}
continue;
bad_cap:
error(0, "WSP: Found illegal value in capabilities reply.");
wsp_cap_dump(cap);
gwlist_delete(caps, i, 1);
i--;
wsp_cap_destroy(cap);
continue;
}
}
static void reply_known_capabilities(List *caps, List *req, WSPMachine *m) {
unsigned long ui;
Capability *cap;
Octstr *data;
if (wsp_cap_count(caps, WSP_CAPS_CLIENT_SDU_SIZE, NULL) == 0) {
if (wsp_cap_get_client_sdu(req, &ui) > 0) {
/* Accept value if it is not silly. */
if ((ui >= 256 && ui < LONG_MAX) || ui == 0) {
m->client_SDU_size = ui;
}
}
/* Reply with the client SDU we decided on */
data = octstr_create("");
octstr_append_uintvar(data, m->client_SDU_size);
cap = wsp_cap_create(WSP_CAPS_CLIENT_SDU_SIZE,
NULL, data);
gwlist_append(caps, cap);
}
if (wsp_cap_count(caps, WSP_CAPS_SERVER_SDU_SIZE, NULL) == 0) {
/* Accept whatever size the client is willing
* to send. If the client did not specify anything,
* then use the default. */
if (wsp_cap_get_server_sdu(req, &ui) <= 0) {
ui = 1400;
}
data = octstr_create("");
octstr_append_uintvar(data, ui);
cap = wsp_cap_create(WSP_CAPS_SERVER_SDU_SIZE, NULL, data);
gwlist_append(caps, cap);
}
/* Currently we cannot handle any protocol options */
if (wsp_cap_count(caps, WSP_CAPS_PROTOCOL_OPTIONS, NULL) == 0) {
data = octstr_create("");
octstr_append_char(data, 0);
cap = wsp_cap_create(WSP_CAPS_PROTOCOL_OPTIONS, NULL, data);
gwlist_append(caps, cap);
}
/* Accept any Method-MOR the client sent; if it sent none,
* use the default. */
if (wsp_cap_count(caps, WSP_CAPS_METHOD_MOR, NULL) == 0) {
if (wsp_cap_get_method_mor(req, &ui) <= 0) {
ui = 1;
}
data = octstr_create("");
octstr_append_char(data, ui);
cap = wsp_cap_create(WSP_CAPS_METHOD_MOR, NULL, data);
gwlist_append(caps, cap);
}
/* We will never send any Push requests because we don't support
* that yet. But we already specified that in protocol options;
* so, pretend we do, and handle the value that way. */
if (wsp_cap_count(caps, WSP_CAPS_PUSH_MOR, NULL) == 0) {
if (wsp_cap_get_push_mor(req, &ui) > 0) {
m->MOR_push = ui;
}
data = octstr_create("");
octstr_append_char(data, m->MOR_push);
cap = wsp_cap_create(WSP_CAPS_PUSH_MOR, NULL, data);
gwlist_append(caps, cap);
}
/* Supporting extended methods is up to the application layer,
* not up to us. If the application layer didn't specify any,
* then we refuse whatever the client requested. The default
* is to support none, so we don't really have to add anything here. */
/* We do not support any header code pages. sanitize_capabilities
* must have already deleted any reply that indicates otherwise.
* Again, not adding anything here is the same as refusing support. */
/* Listing aliases is something the application layer can do if
* it wants to. We don't care. */
}
/* Generate a refusal for all requested capabilities that are not
* replied to. */
static void refuse_unreplied_capabilities(List *caps, List *req) {
long i, len;
Capability *cap;
len = gwlist_len(req);
for (i = 0; i < len; i++) {
cap = gwlist_get(req, i);
if (wsp_cap_count(caps, cap->id, cap->name) == 0) {
cap = wsp_cap_create(cap->id, cap->name, NULL);
gwlist_append(caps, cap);
}
}
}
static int is_default_cap(Capability *cap) {
unsigned long ui;
/* All unknown values are empty by default */
if (cap->name != NULL || cap->id < 0 || cap->id >= WSP_NUM_CAPS)
return cap->data == NULL || octstr_len(cap->data) == 0;
switch (cap->id) {
case WSP_CAPS_CLIENT_SDU_SIZE:
case WSP_CAPS_SERVER_SDU_SIZE:
return (cap->data != NULL &&
octstr_extract_uintvar(cap->data, &ui, 0) >= 0 &&
ui == 1400);
case WSP_CAPS_PROTOCOL_OPTIONS:
return cap->data != NULL && octstr_get_char(cap->data, 0) == 0;
case WSP_CAPS_METHOD_MOR:
case WSP_CAPS_PUSH_MOR:
return cap->data != NULL && octstr_get_char(cap->data, 0) == 1;
case WSP_CAPS_EXTENDED_METHODS:
case WSP_CAPS_HEADER_CODE_PAGES:
case WSP_CAPS_ALIASES:
return cap->data == NULL || octstr_len(cap->data) == 0;
default:
return 0;
}
}
/* Remove any replies that have no corresponding request and that
* are equal to the default. */
static void strip_default_capabilities(List *caps, List *req) {
long i;
Capability *cap;
int count;
/* Hmm, this is an O(N*N) operation, which may be bad. */
i = 0;
while (i < gwlist_len(caps)) {
cap = gwlist_get(caps, i);
count = wsp_cap_count(req, cap->id, cap->name);
if (count == 0 && is_default_cap(cap)) {
gwlist_delete(caps, i, 1);
wsp_cap_destroy(cap);
} else {
i++;
}
}
}
static List *make_capabilities_reply(WSPMachine *m) {
List *caps;
/* In principle, copy the application layer's capabilities
* response, add refusals for all unknown requested capabilities,
* and add responses for all known capabilities that are
* not already responded to. Then eliminate any replies that
* would have no effect because they are equal to the default. */
caps = wsp_cap_duplicate_list(m->reply_caps);
/* Don't let the application layer negotiate anything we
* cannot handle. Also parse the values it set if we're
* interested. */
sanitize_capabilities(caps, m);
/* Add capability records for all capabilities we know about
* that are not already in the reply list. */
reply_known_capabilities(caps, m->request_caps, m);
/* All remaining capabilities in the request list that are
* not in the reply list at this point must be unknown ones
* that we want to refuse. */
refuse_unreplied_capabilities(caps, m->request_caps);
/* Now eliminate replies that would be equal to the requested
* value, or (if there was none) to the default value. */
strip_default_capabilities(caps, m->request_caps);
return caps;
}
static List *make_reply_headers(WSPMachine *m)
{
List *headers;
Octstr *encoding_version;
/* Add all server wsp level hop-by-hop headers. Currently only
* Encoding-Version, as defined by wsp, chapter 8.4.2.70.
* What headers belong to which version is defined in appendix A,
* table 39..
encoding_version = request_version = NULL;
* Essentially, if the client sends us an Encoding-Version
* higher than ours (1.3) we send our version number to it,
* if it is lower, we left version number intact. */
/* First the case that we have no Encoding-Version header at all.
* This case we must assume that the client supports version 1.2
* or lower. */
headers = http_create_empty_headers();
encoding_version = wsp_encoding_version_to_string(m->encoding_version);
http_header_add(headers, "Encoding-Version", octstr_get_cstr(encoding_version));
octstr_destroy(encoding_version);
return headers;
}
static Octstr *make_connectreply_pdu(WSPMachine *m)
{
WSP_PDU *pdu;
Octstr *os;
List *caps;
List *reply_headers;
pdu = wsp_pdu_create(ConnectReply);
pdu->u.ConnectReply.sessionid = m->session_id;
caps = make_capabilities_reply(m);
pdu->u.ConnectReply.capabilities = wsp_cap_pack_list(caps);
wsp_cap_destroy_list(caps);
reply_headers = make_reply_headers(m);
pdu->u.ConnectReply.headers =
wsp_headers_pack(reply_headers, 0, m->encoding_version);
http_destroy_headers(reply_headers);
os = wsp_pdu_pack(pdu);
wsp_pdu_destroy(pdu);
return os;
}
static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers)
{
WSP_PDU *pdu;
Octstr *os;
pdu = wsp_pdu_create(Reply);
/* Not specified for Resume replies */
pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(HTTP_OK);
if (headers == NULL) {
headers = http_create_empty_headers();
pdu->u.Reply.headers = wsp_headers_pack(headers, 1, m->encoding_version);
http_destroy_headers(headers);
} else {
pdu->u.Reply.headers = wsp_headers_pack(headers, 1, m->encoding_version);
}
pdu->u.Reply.data = octstr_create("");
os = wsp_pdu_pack(pdu);
wsp_pdu_destroy(pdu);
return os;
}
static WSP_PDU *make_confirmedpush_pdu(WAPEvent *e)
{
WSP_PDU *pdu;
List *headers;
pdu = wsp_pdu_create(ConfirmedPush);
/*
* Both push headers and push body are optional.
*/
if (e->u.S_ConfirmedPush_Req.push_headers == NULL) {
headers = http_create_empty_headers();
pdu->u.ConfirmedPush.headers = wsp_headers_pack(headers, 1, WSP_1_2);
http_destroy_headers(headers);
} else
pdu->u.ConfirmedPush.headers =
wsp_headers_pack(e->u.S_ConfirmedPush_Req.push_headers, 1, WSP_1_2);
if (e->u.S_ConfirmedPush_Req.push_body == NULL)
pdu->u.ConfirmedPush.data = octstr_create("");
else
pdu->u.ConfirmedPush.data =
octstr_duplicate(e->u.S_ConfirmedPush_Req.push_body);
return pdu;
}
static WSP_PDU *make_push_pdu(WAPEvent *e)
{
WSP_PDU *pdu;
List *headers;
pdu = wsp_pdu_create(Push);
/*
* Both push headers and push body are optional
*/
if (e->u.S_Push_Req.push_headers == NULL) {
headers = http_create_empty_headers();
pdu->u.Push.headers = wsp_headers_pack(headers, 1, WSP_1_2);
http_destroy_headers(headers);
} else
pdu->u.Push.headers =
wsp_headers_pack(e->u.S_Push_Req.push_headers, 1, WSP_1_2);
if (e->u.S_Push_Req.push_body == NULL)
pdu->u.Push.data = octstr_create("");
else
pdu->u.Push.data =
octstr_duplicate(e->u.S_Push_Req.push_body);
return pdu;
}
static int transaction_belongs_to_session(void *wsp_ptr, void *tuple_ptr) {
WSPMachine *wsp;
WAPAddrTuple *tuple;
wsp = wsp_ptr;
tuple = tuple_ptr;
return wap_addr_tuple_same(wsp->addr_tuple, tuple);
}
static int find_by_session_id(void *wsp_ptr, void *id_ptr) {
WSPMachine *wsp = wsp_ptr;
long *idp = id_ptr;
return wsp->session_id == *idp;
}
static int find_by_method_id(void *wspm_ptr, void *id_ptr) {
WSPMethodMachine *msm = wspm_ptr;
long *idp = id_ptr;
return msm->transaction_id == *idp;
}
static int find_by_push_id(void *m_ptr, void *id_ptr) {
WSPPushMachine *m = m_ptr;
long *idp = id_ptr;
return m->transaction_id == *idp;
}
static WSPMethodMachine *find_method_machine(WSPMachine *sm, long id) {
return gwlist_search(sm->methodmachines, &id, find_by_method_id);
}
static WSPPushMachine *find_push_machine(WSPMachine *m, long id)
{
return gwlist_search(m->pushmachines, &id, find_by_push_id);
}
static int same_client(void *a, void *b) {
WSPMachine *sm1, *sm2;
sm1 = a;
sm2 = b;
return wap_addr_tuple_same(sm1->addr_tuple, sm2->addr_tuple);
}
static void disconnect_other_sessions(WSPMachine *sm) {
List *old_sessions;
WAPEvent *disconnect;
WSPMachine *sm2;
long i;
old_sessions = gwlist_search_all(session_machines, sm, same_client);
if (old_sessions == NULL)
return;
for (i = 0; i < gwlist_len(old_sessions); i++) {
sm2 = gwlist_get(old_sessions, i);
if (sm2 != sm) {
disconnect = wap_event_create(Disconnect_Event);
handle_session_event(sm2, disconnect, NULL);
}
}
gwlist_destroy(old_sessions, NULL);
}
static List *unpack_new_headers(WSPMachine *sm, Octstr *hdrs) {
List *new_headers;
if (hdrs && octstr_len(hdrs) > 0) {
new_headers = wsp_headers_unpack(hdrs, 0);
if (sm->http_headers == NULL)
sm->http_headers = http_create_empty_headers();
http_header_combine(sm->http_headers, new_headers);
return new_headers;
}
return NULL;
}
static WAPEvent *make_abort(long reason, long handle)
{
WAPEvent *wtp_event;
wtp_event = wap_event_create(TR_Abort_Req);
wtp_event->u.TR_Abort_Req.abort_type = 0x01;
wtp_event->u.TR_Abort_Req.abort_reason = reason;
wtp_event->u.TR_Abort_Req.handle = handle;
return wtp_event;
}
static void send_abort(long reason, long handle) {
WAPEvent *wtp_event;
wtp_event = make_abort(reason, handle);
dispatch_to_wtp_resp(wtp_event);
}
static void send_abort_to_initiator(long reason, long handle)
{
WAPEvent *wtp_event;
wtp_event = make_abort(reason, handle);
dispatch_to_wtp_init(wtp_event);
}
/*
* The server sends invoke (to be exact, makes TR-Invoke.req) only when it is
* pushing. (Only the client disconnects sessions.)
*/
static void send_invoke(WSPMachine *m, WSP_PDU *pdu, WAPEvent *e, long class)
{
WAPEvent *wtp_event;
wtp_event = wap_event_create(TR_Invoke_Req);
wtp_event->u.TR_Invoke_Req.addr_tuple =
wap_addr_tuple_duplicate(m->addr_tuple);
/*
* There is no mention of acknowledgement type in the specs.But because
* confirmed push is confirmed after response from OTA, provider acknowledge-
* ments seem redundant.
*/
wtp_event->u.TR_Invoke_Req.up_flag = USER_ACKNOWLEDGEMENT;
wtp_event->u.TR_Invoke_Req.tcl = class;
if (e->type == S_ConfirmedPush_Req)
wtp_event->u.TR_Invoke_Req.handle =
e->u.S_ConfirmedPush_Req.server_push_id;
wtp_event->u.TR_Invoke_Req.user_data = wsp_pdu_pack(pdu);
wsp_pdu_destroy(pdu);
dispatch_to_wtp_init(wtp_event);
}
static void indicate_disconnect(WSPMachine *sm, long reason) {
WAPEvent *new_event;
new_event = wap_event_create(S_Disconnect_Ind);
new_event->u.S_Disconnect_Ind.reason_code = reason;
new_event->u.S_Disconnect_Ind.redirect_security = 0;
new_event->u.S_Disconnect_Ind.redirect_addresses = 0;
new_event->u.S_Disconnect_Ind.error_headers = NULL;
new_event->u.S_Disconnect_Ind.error_body = NULL;
new_event->u.S_Disconnect_Ind.session_handle = sm->session_id;
dispatch_to_appl(new_event);
}
static void indicate_suspend(WSPMachine *sm, long reason) {
WAPEvent *new_event;
new_event = wap_event_create(S_Suspend_Ind);
new_event->u.S_Suspend_Ind.reason = reason;
new_event->u.S_Suspend_Ind.session_id = sm->session_id;
dispatch_to_appl(new_event);
}
static void indicate_resume(WSPMachine *sm,
WAPAddrTuple *tuple, List *headers) {
WAPEvent *new_event;
new_event = wap_event_create(S_Resume_Ind);
new_event->u.S_Resume_Ind.addr_tuple = wap_addr_tuple_duplicate(tuple);
new_event->u.S_Resume_Ind.client_headers = http_header_duplicate(headers);
new_event->u.S_Resume_Ind.session_id = sm->session_id;
dispatch_to_appl(new_event);
}
static void indicate_pushabort(WSPPushMachine *spm, long reason)
{
WAPEvent *ota_event;
ota_event = wap_event_create(S_PushAbort_Ind);
ota_event->u.S_PushAbort_Ind.push_id = spm->server_push_id;
ota_event->u.S_PushAbort_Ind.reason = reason;
ota_event->u.S_PushAbort_Ind.session_id = spm->session_id;
dispatch_to_appl(ota_event);
}
static void confirm_push(WSPPushMachine *m)
{
WAPEvent *ota_event;
ota_event = wap_event_create(S_ConfirmedPush_Cnf);
ota_event->u.S_ConfirmedPush_Cnf.server_push_id = m->server_push_id;
ota_event->u.S_ConfirmedPush_Cnf.session_id = m->session_id;
dispatch_to_appl(ota_event);
}
static void method_abort(WSPMethodMachine *msm, long reason) {
WAPEvent *wtp_event;
/* Send TR-Abort.req(reason) */
wtp_event = wap_event_create(TR_Abort_Req);
/* FIXME: Specs are unclear about this; we may indeed have to
* guess abort whether this is a WSP or WTP level abort code */
if (reason < WSP_ABORT_PROTOERR) {
wtp_event->u.TR_Abort_Req.abort_type = 0x00;
} else {
wtp_event->u.TR_Abort_Req.abort_type = 0x01;
}
wtp_event->u.TR_Abort_Req.abort_reason = reason;
wtp_event->u.TR_Abort_Req.handle = msm->transaction_id;
dispatch_to_wtp_resp(wtp_event);
}
static void indicate_method_abort(WSPMethodMachine *msm, long reason) {
WAPEvent *new_event;
/* Send S-MethodAbort.ind(reason) */
new_event = wap_event_create(S_MethodAbort_Ind);
new_event->u.S_MethodAbort_Ind.transaction_id = msm->transaction_id;
new_event->u.S_MethodAbort_Ind.reason = reason;
new_event->u.S_MethodAbort_Ind.session_handle = msm->session_id;
dispatch_to_appl(new_event);
}
static int method_is_holding(void *item, void *pattern) {
WSPMethodMachine *msm = item;
return msm->state == HOLDING;
}
static void release_holding_methods(WSPMachine *sm) {
WAPEvent *release;
WSPMethodMachine *msm;
List *holding;
long i, len;
holding = gwlist_search_all(sm->methodmachines, NULL, method_is_holding);
if (holding == NULL)
return;
/* We can re-use this because wsp_handle_method_event does not
* destroy its event */
release = wap_event_create(Release_Event);
len = gwlist_len(holding);
for (i = 0; i < len; i++) {
msm = gwlist_get(holding, i);
handle_method_event(sm, msm, release, NULL);
}
gwlist_destroy(holding, NULL);
wap_event_destroy(release);
}
static void abort_methods(WSPMachine *sm, long reason) {
WAPEvent *ab;
WSPMethodMachine *msm;
long i, len;
ab = wap_event_create(Abort_Event);
ab->u.Abort_Event.reason = reason;
/* This loop goes backward because it has to deal with the
* possibility of method machines disappearing after their event. */
len = gwlist_len(sm->methodmachines);
for (i = len - 1; i >= 0; i--) {
msm = gwlist_get(sm->methodmachines, i);
handle_method_event(sm, msm, ab, NULL);
}
wap_event_destroy(ab);
}
static void abort_pushes(WSPMachine *sm, long reason)
{
WAPEvent *ab;
WSPPushMachine *psm;
long i, len;
ab = wap_event_create(Abort_Event);
ab->u.Abort_Event.reason = reason;
len = gwlist_len(sm->pushmachines);
for (i = len - 1; i >= 0; i--) {
psm = gwlist_get(sm->pushmachines, i);
handle_push_event(sm, psm, ab);
}
wap_event_destroy(ab);
}
WSPMachine *find_session_machine_by_id (int id) {
return gwlist_search(session_machines, &id, id_belongs_to_session);
}
static int id_belongs_to_session (void *wsp_ptr, void *pid) {
WSPMachine *wsp;
int *id;
wsp = wsp_ptr;
id = (int *) pid;
if (*id == wsp->session_id) return 1;
return 0;
}
static int wsp_encoding_string_to_version(Octstr *enc)
{
int v;
/* default will be WSP 1.2, as defined by WAPWSP */
v = WSP_1_2;
if (octstr_compare(enc, octstr_imm("1.1")) == 0) {
v = WSP_1_1;
}
else if (octstr_compare(enc, octstr_imm("1.2")) == 0) {
v = WSP_1_2;
}
else if (octstr_compare(enc, octstr_imm("1.3")) == 0) {
v = WSP_1_3;
}
else if (octstr_compare(enc, octstr_imm("1.4")) == 0) {
v = WSP_1_4;
}
else if (octstr_compare(enc, octstr_imm("1.5")) == 0) {
v = WSP_1_5;
}
return v;
}
static Octstr *wsp_encoding_version_to_string(int version)
{
Octstr *os;
switch (version) {
case WSP_1_1:
os = octstr_create("1.1");
break;
case WSP_1_2:
os = octstr_create("1.2");
break;
case WSP_1_3:
os = octstr_create("1.3");
break;
case WSP_1_4:
os = octstr_create("1.4");
break;
case WSP_1_5:
os = octstr_create("1.5");
break;
default:
os = octstr_create("1.2");
break;
}
return os;
}
gateway-1.4.3/wap/wtls_machine-decl.h 0000644 0001750 0001750 00000015577 11132672002 016551 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtls_machine-decl.h - macro call for generating WTLS server state machine. See
* the architecture document for guidance how to use and update it.
*
* By Nick Clarey (c) 3GLab Ltd.
*
* The WTLSMachine data structure preserves the state of the existing WTLS
* transaction. The fields which are included;
*
* Machine identification: address four-tuple
* Connection End : Server (1) or Client (2) This is always "server"
* (at least at the moment)
* Bulk Cipher Algorithm : The algorithm to be used for stream or block encryption
* Key Size : ?????
* IV Size : The base IV used to calculate a record level IV for block ciphers running
* in CBC mode for records sent by the server
* MAC Algorithm : The algorithm identifier used for message authentication.
* Master Secret : A shared secret between the two peers
* Client Random : A random value supplied by the client
* Server Random : A random value supplied by the server
* Sequence Number Mode : Off (0), Implicit (1) or Explicit (2)
* Key Refresh rate : New keys for MAC secret, IV and Encryption are calculated
* every "n", where n = 2^(RefreshRate)
* Compression Method : The algorithm to compress data prior to encryption
*
*/
#if !defined(MACHINE)
#error "wtls_machine-decl.h: Macro MACHINE is missing."
#elif !defined(ENUM)
#error "wtls_machine-decl.h: Macro ENUM is missing."
#elif !defined(ADDRTUPLE)
#error "wtls_machine-decl.h: Macro ADDRTUPLE is missing."
#elif !defined(INTEGER)
#error "wtls_machine-decl.h: Macro INTEGER is missing."
#elif !defined(OCTSTR)
#error "wtls_machine-decl.h: Macro OCTSTR is missing."
#elif !defined(PDULIST)
#error "wtls_machine-decl.h: Macro PDULIST is missing."
#endif
/* Need to add server sent and client received packets for sequence numbering */
/* Last received packet maybe needs to be hashed according to Alert message in
case we need to send an alert. */
MACHINE(ENUM(state)
ADDRTUPLE(addr_tuple) /* The source address/port and dest address/port */
INTEGER(bulk_cipher_algorithm) /* Bulk Cipher Algorithm identifier */
INTEGER(cipher_type) /* Cipher type */
INTEGER(mac_algorithm) /* MAC Algorithm identifier */
OCTSTR(client_random) /* The client's random number */
OCTSTR(server_random) /* The server's random number */
OCTSTR(master_secret) /* The master secret */
INTEGER (key_size) /* The "key size". Which key size, I have no idea */
INTEGER (key_material_length) /* and what might that be ? */
INTEGER (is_exportable) /* exportable flag (?) */
INTEGER(iv_size) /* The IV size */
INTEGER(mac_size) /* MAC size */
INTEGER(mac_key_size) /* MAC key size */
INTEGER(sequence_number_mode) /* The sequence number mode */
INTEGER(key_refresh) /* How often we should refresh our keys */
OCTSTR(compression_method) /* The compression algorithm */
INTEGER(encrypted) /* set if packets are encrypted */
OCTSTR(client_write_MAC_secret) /* */
OCTSTR(client_write_enc_key) /* */
OCTSTR(client_write_IV) /* */
OCTSTR(server_write_MAC_secret) /* */
OCTSTR(server_write_enc_key) /* */
OCTSTR(server_write_IV) /* */
INTEGER(client_seq_num) /* incremented for each client msg */
INTEGER(server_seq_num) /* incremented for each server msg */
OCTSTR(last_packet_checksum) /* The last received packet checksum */
PDULIST(last_received_packet) /* The last received packet checksum */
OCTSTR(handshake_data) /* All the handshake payloads, received or sent,
concatenated in order */
OCTSTR(packet_to_send) /* A packet we're preparing to send */
)
#undef MACHINE
#undef ENUM
#undef ADDRTUPLE
#undef INTEGER
#undef OCTSTR
#undef PDULIST
gateway-1.4.3/wap/wsp_caps.h 0000644 0001750 0001750 00000011633 11132672002 014773 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wsp_caps.h - interface to WSP capability negotiation
*
* Richard Braakman
*/
#ifndef WSP_CAPS_H
#define WSP_CAPS_H
#include "gwlib/gwlib.h"
struct capability {
/* One or the other of these is set. id is only meaningful
* if name is NULL. (Unfortunately the WSP spec does not
* really assign names to the numeric ids, so we can't translate
* them all to text.) */
int id;
Octstr *name;
/* Raw data for this capability. Can be NULL if there is none. */
Octstr *data;
/* If data is NULL, this field determines if the request should
* be accepted or rejected. */
int accept;
};
typedef struct capability Capability;
/* See table 37 */
enum known_caps {
WSP_CAPS_CLIENT_SDU_SIZE = 0,
WSP_CAPS_SERVER_SDU_SIZE = 1,
WSP_CAPS_PROTOCOL_OPTIONS = 2,
WSP_CAPS_METHOD_MOR = 3,
WSP_CAPS_PUSH_MOR = 4,
WSP_CAPS_EXTENDED_METHODS = 5,
WSP_CAPS_HEADER_CODE_PAGES = 6,
WSP_CAPS_ALIASES = 7,
WSP_NUM_CAPS
};
/* Create a new Capability structure. For numbered capabilities (which
* is all of the known ones), use NULL for the name. The data may also
* be NULL. */
Capability *wsp_cap_create(int id, Octstr *name, Octstr *data);
void wsp_cap_destroy(Capability *cap);
void wsp_cap_dump(Capability *cap);
void wsp_cap_dump_list(List *caps_list);
/* Destroy all Capabilities in a list, as well as the list itself. */
void wsp_cap_destroy_list(List *caps_list);
/* Duplicate a list of Capabilities */
List *wsp_cap_duplicate_list(List *cap);
Capability *wsp_cap_duplicate(Capability *cap);
/* Return a list of Capability structures */
List *wsp_cap_unpack_list(Octstr *caps);
/* Encode a list of Capability structures according to the WSP spec */
Octstr *wsp_cap_pack_list(List *caps_list);
/* Access functions. All of them return the number of requests that
* match the capability being searched for, and if they have an output
* parameter, they set it to the value of the first such request. */
int wsp_cap_count(List *caps_list, int id, Octstr *name);
int wsp_cap_get_client_sdu(List *caps_list, unsigned long *sdu);
int wsp_cap_get_server_sdu(List *caps_list, unsigned long *sdu);
int wsp_cap_get_method_mor(List *caps_list, unsigned long *mor);
int wsp_cap_get_push_mor(List *caps_list, unsigned long *mor);
#endif
gateway-1.4.3/wap/wsp_caps.c 0000644 0001750 0001750 00000021352 11132672002 014765 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wsp_caps.c - implement interface to WSP capability negotiation
*
* Richard Braakman
*/
#include "gwlib/gwlib.h"
#include "wsp_caps.h"
static void wsp_cap_destroy_item(void *cap) {
wsp_cap_destroy(cap);
}
Capability *wsp_cap_create(int id, Octstr *name, Octstr *data) {
Capability *new_cap;
new_cap = gw_malloc(sizeof(*new_cap));
new_cap->id = id;
new_cap->name = name;
new_cap->data = data;
new_cap->accept = 0;
return new_cap;
}
void wsp_cap_destroy(Capability *cap) {
if (cap == NULL)
return;
octstr_destroy(cap->name);
octstr_destroy(cap->data);
gw_free(cap);
}
void wsp_cap_dump(Capability *cap) {
debug("wsp", 0, "Dumping capability at %p:", cap);
if (cap) {
debug("wsp", 0, " id = %d", cap->id);
debug("wsp", 0, " name:");
octstr_dump(cap->name, 1);
debug("wsp", 0, " data:");
octstr_dump(cap->data, 1);
if (cap->data == NULL)
debug("wsp", 0, " accept: %d", cap->accept);
}
debug("wsp", 0, "Capability dump ends.");
}
void wsp_cap_dump_list(List *caps_list) {
long i;
if (caps_list == NULL) {
debug("wsp", 0, "NULL capability list");
return;
}
debug("wsp", 0, "Dumping capability list at %p, length %ld",
caps_list, gwlist_len(caps_list));
for (i = 0; i < gwlist_len(caps_list); i++) {
wsp_cap_dump(gwlist_get(caps_list, i));
}
debug("wsp", 0, "End of capability list dump");
}
void wsp_cap_destroy_list(List *caps_list) {
gwlist_destroy(caps_list, wsp_cap_destroy_item);
}
List *wsp_cap_duplicate_list(List *caps_list) {
Capability *cap;
List *new_list;
long i;
new_list = gwlist_create();
if (caps_list == NULL)
return new_list;
for (i = 0; i < gwlist_len(caps_list); i++) {
cap = gwlist_get(caps_list, i);
gwlist_append(new_list, wsp_cap_duplicate(cap));
}
return new_list;
};
Capability *wsp_cap_duplicate(Capability *cap) {
Capability *new_cap;
if (!cap)
return NULL;
new_cap = wsp_cap_create(cap->id,
octstr_duplicate(cap->name),
octstr_duplicate(cap->data));
new_cap->accept = cap->accept;
return new_cap;
}
List *wsp_cap_unpack_list(Octstr *caps) {
List *caps_list;
long pos, capslen;
caps_list = gwlist_create();
if (caps == NULL)
return caps_list;
capslen = octstr_len(caps);
pos = 0;
while (pos < capslen) {
unsigned long length;
int id;
Octstr *name;
Octstr *data;
pos = octstr_extract_uintvar(caps, &length, pos);
if (pos < 0 || length == 0)
goto error;
id = octstr_get_char(caps, pos);
if (id >= 0x80) {
id &= 0x7f; /* It's encoded as a short-integer */
name = NULL;
data = octstr_copy(caps, pos + 1, length - 1);
} else {
long nullpos;
id = -1; /* It's encoded as token-text */
nullpos = octstr_search_char(caps, 0, pos);
if (nullpos < 0)
goto error;
/* check length
* FIXME: If it's not allowed that data is empty then change check
* to <= .
*/
if (length < (nullpos + 1 - pos))
goto error;
name = octstr_copy(caps, pos, nullpos - pos);
data = octstr_copy(caps, nullpos + 1,
length - (nullpos + 1 - pos));
}
gwlist_append(caps_list, wsp_cap_create(id, name, data));
pos += length;
}
return caps_list;
error:
warning(0, "WSP: Error unpacking capabilities");
return caps_list;
}
Octstr *wsp_cap_pack_list(List *caps_list) {
Octstr *result;
Capability *cap;
long i, len;
result = octstr_create("");
len = gwlist_len(caps_list);
for (i = 0; i < len; i++) {
long datalen;
cap = gwlist_get(caps_list, i);
datalen = 0;
if (cap->data)
datalen = octstr_len(cap->data);
if (datalen == 0 && cap->accept)
continue;
if (cap->name) {
if (octstr_get_char(cap->name, 0) >= 0x80 ||
octstr_search_char(cap->name, 0, 0) >= 0) {
error(0, "WSP: Bad capability.");
wsp_cap_dump(cap);
continue;
}
/* Add length */
octstr_append_uintvar(result,
octstr_len(cap->name) + 1 + datalen);
/* Add identifier */
octstr_append(result, cap->name);
octstr_append_char(result, 0);
} else {
if (cap->id >= 0x80 || cap->id < 0) {
error(0, "WSP: Bad capability.");
wsp_cap_dump(cap);
continue;
}
/* Add length */
octstr_append_uintvar(result, 1 + datalen);
/* Add identifier */
octstr_append_char(result, 0x80 | cap->id);
}
/* Add payload, if any */
if (cap->data) {
octstr_append(result, cap->data);
}
}
return result;
}
static int wsp_cap_get_data(List *caps_list, int id, Octstr *name,
Octstr **data) {
long i, len;
Capability *cap;
int found;
len = gwlist_len(caps_list);
found = 0;
*data = NULL;
for (i = 0; i < len; i++) {
cap = gwlist_get(caps_list, i);
if ((name && cap->name
&& octstr_compare(name, cap->name) == 0)
|| (!name && cap->id == id)) {
if (!found)
*data = cap->data;
found++;
}
}
return found;
}
int wsp_cap_count(List *caps_list, int id, Octstr *name) {
Octstr *data;
return wsp_cap_get_data(caps_list, id, name, &data);
}
int wsp_cap_get_client_sdu(List *caps_list, unsigned long *sdu) {
Octstr *data;
int found;
found = wsp_cap_get_data(caps_list, WSP_CAPS_CLIENT_SDU_SIZE,
NULL, &data);
if (found > 0 && octstr_extract_uintvar(data, sdu, 0) < 0)
return -1;
return found;
}
int wsp_cap_get_server_sdu(List *caps_list, unsigned long *sdu) {
Octstr *data;
int found;
found = wsp_cap_get_data(caps_list, WSP_CAPS_SERVER_SDU_SIZE,
NULL, &data);
if (found > 0 && octstr_extract_uintvar(data, sdu, 0) < 0)
return -1;
return found;
}
int wsp_cap_get_method_mor(List *caps_list, unsigned long *mor) {
Octstr *data;
int found;
int c;
found = wsp_cap_get_data(caps_list, WSP_CAPS_METHOD_MOR, NULL, &data);
if (found > 0) {
c = octstr_get_char(data, 0);
if (c < 0)
return -1;
*mor = c;
}
return found;
}
int wsp_cap_get_push_mor(List *caps_list, unsigned long *mor) {
Octstr *data;
int found;
int c;
found = wsp_cap_get_data(caps_list, WSP_CAPS_PUSH_MOR, NULL, &data);
if (found > 0) {
c = octstr_get_char(data, 0);
if (c < 0)
return -1;
*mor = c;
}
return found;
}
gateway-1.4.3/wap/wsp_pdu.h 0000644 0001750 0001750 00000010421 11132672002 014627 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wsp_pdu.h - definitions for unpacked WTP protocol data units
*
* This file generates a structure definition and some function
* declarations from wtp_pdu.def, using preprocessor magic.
*
* Richard Braakman
*/
#ifndef WSP_PDU_H
#define WSP_PDU_H
#include "gwlib/gwlib.h"
/* The Get and Post PDUs contain a "subtype" field. Sometimes we
* have to reconstruct the full method number. For methods encoded
* in Get PDUs, this is GET_METHODS + subtype. For methods encoded
* in Post PDUs, this is POST_METHODS + subtype. */
enum {
GET_METHODS = 0x40,
POST_METHODS = 0x60
};
/* Enumerate the symbolic names of the PDUs */
enum wsp_pdu_types {
#define PDU(name, docstring, fields, is_valid) name,
#include "wsp_pdu.def"
#undef PDU
};
struct wsp_pdu {
int type;
union {
/* For each PDU, declare a structure with its fields, named after the PDU */
#define PDU(name, docstring, fields, is_valid) struct name { fields } name;
#define UINT(field, docstring, bits) unsigned long field;
#define UINTVAR(field, docstring) unsigned long field;
#define OCTSTR(field, docstring, lengthfield) Octstr *field;
#define REST(field, docstring) Octstr *field;
#define TYPE(bits, value)
#define RESERVED(bits)
#define TPI(confield)
#include "wsp_pdu.def"
#undef TPI
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
} u;
};
typedef struct wsp_pdu WSP_PDU;
WSP_PDU *wsp_pdu_create(int type);
WSP_PDU *wsp_pdu_unpack(Octstr *data);
Octstr *wsp_pdu_pack(WSP_PDU *pdu);
void wsp_pdu_dump(WSP_PDU *pdu, int level);
void wsp_pdu_destroy(WSP_PDU *pdu);
#endif
gateway-1.4.3/wap/wsp_strings.c 0000644 0001750 0001750 00000023127 11132672003 015533 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wsp_strings.c: lookup code for various tables defined by WSP standard
*
* This file provides functions to translate strings to numbers and numbers
* to strings according to the Assigned Numbers tables in appendix A
* of the WSP specification.
*
* The tables are in wsp_strings.def, in a special format suitable for
* use with the C preprocessor, which we abuse liberally to get the
* interface we want.
*
* Richard Braakman
*/
#include "gwlib/gwlib.h"
#include "wsp_strings.h"
#define TABLE_SIZE(table) ((long)(sizeof(table) / sizeof(table[0])))
static int initialized;
/* The arrays in a table structure are all of equal length, and their
* elements correspond. The number for string 0 is in numbers[0], etc.
* Table structures are initialized dynamically.
*/
struct table
{
long size; /* Nr of entries in each of the tables below */
Octstr **strings; /* Immutable octstrs */
long *numbers; /* Assigned numbers, or NULL for linear tables */
int *versions; /* WSP Encoding-versions, or NULL if non-versioned */
int linear; /* True for tables defined as LINEAR */
};
struct numbered_element
{
char *str;
long number;
int version;
};
struct linear_element
{
char *str;
int version;
};
/* Local functions */
static Octstr *number_to_string(long number, struct table *table);
static unsigned char *number_to_cstr(long number, struct table *table);
static long string_to_number(Octstr *ostr, struct table *table);
static long string_to_versioned_number(Octstr *ostr, struct table *table, int version);
/* Declare the data. For each table "foo", create a foo_strings array
* to hold the data, and a (still empty) foo_table structure. */
#define LINEAR(name, strings) \
static const struct linear_element name##_strings[] = { strings }; \
static struct table name##_table;
#define STRING(string) { string, 0 },
#define VSTRING(version, string) { string, version },
#define NUMBERED(name, strings) \
static const struct numbered_element name##_strings[] = { strings }; \
static struct table name##_table;
#define ASSIGN(string, number) { string, number, 0 },
#define VASSIGN(version, string, number) { string, number, version },
#include "wsp_strings.def"
/* Define the functions for translating number to Octstr */
#define LINEAR(name, strings) \
Octstr *wsp_##name##_to_string(long number) { \
return number_to_string(number, &name##_table); \
}
#include "wsp_strings.def"
/* Define the functions for translating number to constant string */
#define LINEAR(name, strings) \
unsigned char *wsp_##name##_to_cstr(long number) { \
return number_to_cstr(number, &name##_table); \
}
#include "wsp_strings.def"
#define LINEAR(name, strings) \
long wsp_string_to_##name(Octstr *ostr) { \
return string_to_number(ostr, &name##_table); \
}
#include "wsp_strings.def"
#define LINEAR(name, strings) \
long wsp_string_to_versioned_##name(Octstr *ostr, int version) { \
return string_to_versioned_number(ostr, &name##_table, version); \
}
#include "wsp_strings.def"
static Octstr *number_to_string(long number, struct table *table)
{
long i;
gw_assert(initialized);
if (table->linear) {
if (number >= 0 && number < table->size)
return octstr_duplicate(table->strings[number]);
} else {
for (i = 0; i < table->size; i++) {
if (table->numbers[i] == number)
return octstr_duplicate(table->strings[i]);
}
}
return NULL;
}
static unsigned char *number_to_cstr(long number, struct table *table)
{
long i;
gw_assert(initialized);
if (table->linear) {
if (number >= 0 && number < table->size)
return (unsigned char *)octstr_get_cstr(table->strings[number]);
} else {
for (i = 0; i < table->size; i++) {
if (table->numbers[i] == number)
return (unsigned char *)octstr_get_cstr(table->strings[i]);
}
}
return NULL;
}
/* Case-insensitive string lookup */
static long string_to_number(Octstr *ostr, struct table *table)
{
long i;
gw_assert(initialized);
for (i = 0; i < table->size; i++) {
if (octstr_case_compare(ostr, table->strings[i]) == 0) {
return table->linear ? i : table->numbers[i];
}
}
return -1;
}
/* Case-insensitive string lookup according to passed WSP encoding version */
static long string_to_versioned_number(Octstr *ostr, struct table *table,
int version)
{
long i, ret;
gw_assert(initialized);
/* walk the whole table and pick the highest versioned token */
ret = -1;
for (i = 0; i < table->size; i++) {
if (octstr_case_compare(ostr, table->strings[i]) == 0 &&
table->versions[i] <= version) {
ret = table->linear ? i : table->numbers[i];
}
}
debug("wsp.strings",0,"WSP: Mapping `%s', WSP 1.%d to 0x%04lx.",
octstr_get_cstr(ostr), version, ret);
return ret;
}
static void construct_linear_table(struct table *table, const struct linear_element *strings,
long size)
{
long i;
table->size = size;
table->strings = gw_malloc(size * (sizeof table->strings[0]));
table->numbers = NULL;
table->versions = gw_malloc(size * (sizeof table->versions[0]));
table->linear = 1;
for (i = 0; i < size; i++) {
table->strings[i] = octstr_imm(strings[i].str);
table->versions[i] = strings[i].version;
}
}
static void construct_numbered_table(struct table *table, const struct numbered_element *strings,
long size)
{
long i;
table->size = size;
table->strings = gw_malloc(size * (sizeof table->strings[0]));
table->numbers = gw_malloc(size * (sizeof table->numbers[0]));
table->versions = gw_malloc(size * (sizeof table->versions[0]));
table->linear = 0;
for (i = 0; i < size; i++) {
table->strings[i] = octstr_imm(strings[i].str);
table->numbers[i] = strings[i].number;
table->versions[i] = strings[i].version;
}
}
static void destroy_table(struct table *table)
{
/* No need to call octstr_destroy on immutable octstrs */
gw_free(table->strings);
gw_free(table->numbers);
gw_free(table->versions);
}
void wsp_strings_init(void)
{
if (initialized > 0) {
initialized++;
return;
}
#define LINEAR(name, strings) \
construct_linear_table(&name##_table, \
name##_strings, TABLE_SIZE(name##_strings));
#define NUMBERED(name, strings) \
construct_numbered_table(&name##_table, \
name##_strings, TABLE_SIZE(name##_strings));
#include "wsp_strings.def"
initialized++;
}
void wsp_strings_shutdown(void)
{
/* If we were initialized more than once, then wait for more than
* one shutdown. */
if (initialized > 1) {
initialized--;
return;
}
#define LINEAR(name, strings) \
destroy_table(&name##_table);
#include "wsp_strings.def"
initialized = 0;
}
gateway-1.4.3/wap/wsp_server_session_states.def 0000644 0001750 0001750 00000072437 11132672003 021022 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_server_session_states.def - states for WSP session state machines
*
* Macro calls to generate rows of the state table. See the documentation for
* guidance how to use and update these.
*
* Note that `NULL' state is renamed to `NULL_SESSION' because NULL is
* reserved by C.
*
* Lars Wirzenius
*/
STATE_NAME(NULL_SESSION)
STATE_NAME(CONNECTING)
STATE_NAME(TERMINATING)
STATE_NAME(CONNECTING_2)
STATE_NAME(CONNECTED)
STATE_NAME(SUSPENDED)
STATE_NAME(RESUMING)
STATE_NAME(RESUMING_2)
ROW(NULL_SESSION,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Connect,
{
WAPEvent *new_event;
WAPEvent *wtp_event;
/* Send TR-Invoke.res to WTP */
wtp_event = wap_event_create(TR_Invoke_Res);
wtp_event->u.TR_Invoke_Res.handle = e->handle;
dispatch_to_wtp_resp(wtp_event);
/* Assign a session ID for this session. We do this
* early, instead of in the CONNECTING state, because
* we want to use the session id as a way for the
* application layer to refer back to this machine. */
sm->session_id = next_wsp_session_id();
if (pdu->u.Connect.capabilities_len > 0) {
unsigned long sdu;
sm->request_caps = wsp_cap_unpack_list(
pdu->u.Connect.capabilities);
if (wsp_cap_get_client_sdu(sm->request_caps,&sdu)) {
sm->client_SDU_size = sdu;
}
} else {
sm->request_caps = gwlist_create();
}
if (pdu->u.Connect.headers_len > 0) {
List *hdrs;
Octstr *encoding;
hdrs = wsp_headers_unpack(pdu->u.Connect.headers, 0);
http_header_pack(hdrs);
gw_assert(sm->http_headers == NULL);
sm->http_headers = hdrs;
/*
* Get WSP encoding version if provided by device and remember in
* session machine for later use in encoding tokenized values.
*/
encoding = http_header_value(sm->http_headers, octstr_imm("Encoding-Version"));
if (encoding != NULL) {
debug("wsp",0,"WSP: Session machine: Encoding-Version: %s",
octstr_get_cstr(encoding));
sm->encoding_version = wsp_encoding_string_to_version(encoding);
} else {
/* WAP-230-WSP-20010705-a, section 8.4.2.70, page 97 defines
* by a MUST argument that a non-present Encoding-Version header
* should be interpreted as WSP 1.2 compliant.
*/
sm->encoding_version = WSP_1_2;
}
octstr_destroy(encoding);
}
/* Send S-Connect.ind to application layer */
new_event = wap_event_create(S_Connect_Ind);
new_event->u.S_Connect_Ind.addr_tuple =
wap_addr_tuple_duplicate(e->addr_tuple);
new_event->u.S_Connect_Ind.client_headers =
http_header_duplicate(sm->http_headers);
new_event->u.S_Connect_Ind.requested_capabilities =
wsp_cap_duplicate_list(sm->request_caps);
new_event->u.S_Connect_Ind.session_id = sm->session_id;
dispatch_to_appl(new_event);
},
CONNECTING)
ROW(CONNECTING,
S_Connect_Res,
1,
{
WAPEvent *wtp_event;
Octstr *ospdu;
sm->reply_caps = wsp_cap_duplicate_list(
e->negotiated_capabilities);
/* Send Disconnect event to existing sessions for client. */
disconnect_other_sessions(sm);
/* Assign a Session_ID for this session. */
/* We've already done that in the NULL_STATE. */
/* TR-Result.req(ConnectReply) */
ospdu = make_connectreply_pdu(sm);
wtp_event = wap_event_create(TR_Result_Req);
wtp_event->u.TR_Result_Req.user_data = ospdu;
wtp_event->u.TR_Result_Req.handle = sm->connect_handle;
dispatch_to_wtp_resp(wtp_event);
/* Release all method transactions in HOLDING state. */
release_holding_methods(sm);
},
CONNECTING_2)
/* MISSING: CONNECTING, S_Disconnect_Req, reason == 301 (moved permanently) or
* 302 (moved temporarily). */
/* MISSING: CONNECTING, S_Disconnect_Req, reason == anything else */
ROW(CONNECTING,
Disconnect_Event,
1,
{
/* TR-Abort.req(DISCONNECT) the Connect transaction */
send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle);
/* Abort(DISCONNECT) all method transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(CONNECTING,
Suspend_Event,
1,
{
/* TR-Abort.req(DISCONNECT) the Connect transaction */
send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle);
/* Abort(DISCONNECT) all method transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(SUSPEND) */
indicate_disconnect(sm, WSP_ABORT_SUSPEND);
},
NULL_SESSION)
ROW(CONNECTING,
TR_Invoke_Ind,
e->tcl == 2 && (pdu->type == Get || pdu->type == Post),
{
WSPMethodMachine *msm;
/* Start new method transaction */
msm = method_machine_create(sm, e->handle);
/* Hand off the event to the new method machine */
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTING)
ROW(CONNECTING,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Resume,
{
/* TR-Abort.req(DISCONNECT) the TR-Invoke */
send_abort(WSP_ABORT_DISCONNECT, e->handle);
},
CONNECTING)
ROW(CONNECTING,
TR_Abort_Ind,
e->handle == sm->connect_handle,
{
/* Abort(DISCONNECT) all method transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(abort reason) */
indicate_disconnect(sm, e->abort_code);
},
NULL_SESSION)
ROW(CONNECTING,
TR_Abort_Ind,
e->handle != sm->connect_handle,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTING)
ROW(TERMINATING,
Disconnect_Event,
1,
{
/* TR-Abort.req(DISCONNECT) remaining transport transaction */
send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle);
},
NULL_SESSION)
ROW(TERMINATING,
Suspend_Event,
1,
{
/* TR-Abort.req(SUSPEND) remaining transport transaction */
send_abort(WSP_ABORT_SUSPEND, sm->connect_handle);
},
NULL_SESSION)
ROW(TERMINATING,
TR_Result_Cnf,
1,
{
/* Ignore */
},
NULL_SESSION)
ROW(TERMINATING,
TR_Abort_Ind,
1,
{
/* Ignore */
},
NULL_SESSION)
/* MISSING: CONNECTING_2, S-Disconnect.req */
ROW(CONNECTING_2,
Disconnect_Event,
1,
{
/* TR-Abort.req(DISCONNECT) the Connect transaction */
send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle);
/* Abort(DISCONNECT) all method and push transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(CONNECTING_2,
S_MethodInvoke_Res,
1,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->server_transaction_id);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTING_2)
ROW(CONNECTING_2,
S_MethodResult_Req,
1,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->server_transaction_id);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTING_2)
ROW(CONNECTING_2,
S_Push_Req,
1,
{
WSP_PDU *pdu;
pdu = make_push_pdu(current_event);
send_invoke(sm, pdu, current_event, TRANSACTION_CLASS_0);
},
CONNECTING_2)
ROW(CONNECTING_2,
S_ConfirmedPush_Req,
1,
{
/* Start new push transaction*/
WSPPushMachine *spm;
spm = push_machine_create(sm, e->server_push_id);
handle_push_event(sm, spm, current_event);
},
CONNECTING_2)
ROW(CONNECTING_2,
Suspend_Event,
!resume_enabled,
{
/* Session Resume facility disabled */
/* TR-Abort.req(DISCONNECT) the Connect transaction */
send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle);
/* Abort(DISCONNECT) all method and push transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(SUSPEND) */
indicate_disconnect(sm, WSP_ABORT_SUSPEND);
},
NULL_SESSION)
ROW(CONNECTING_2,
Suspend_Event,
resume_enabled,
{
/* Session Resume facility enabled */
/* TR-Abort.req(SUSPEND) the Connect transaction */
send_abort(WSP_ABORT_SUSPEND, sm->connect_handle);
/* Abort(SUSPEND) all method and push transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(SUSPEND) */
indicate_suspend(sm, WSP_ABORT_SUSPEND);
},
SUSPENDED)
ROW(CONNECTING_2,
TR_Invoke_Ind,
e->tcl == 2 && (pdu->type == Get || pdu->type == Post),
{
WSPMethodMachine *msm;
WAPEvent *new_event;
/* Start new method transaction */
msm = method_machine_create(sm, e->handle);
/* Hand off the event to the new method machine */
handle_method_event(sm, msm, current_event, pdu);
/* Release the new method transaction */
new_event = wap_event_create(Release_Event);
handle_method_event(sm, msm, new_event, NULL);
wap_event_destroy(new_event);
},
CONNECTING_2)
ROW(CONNECTING_2,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Resume && !resume_enabled,
{
/* Resume facility disabled */
/* TR-Abort.req(DISCONNECT) the TR-Invoke */
send_abort(WSP_ABORT_DISCONNECT, e->handle);
},
CONNECTING_2)
ROW(CONNECTING_2,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Resume && resume_enabled,
{
/* Resume facility enabled */
WAPEvent *wtp_event;
List *new_headers;
/* TR-Invoke.res */
wtp_event = wap_event_create(TR_Invoke_Res);
wtp_event->u.TR_Invoke_Res.handle = e->handle;
dispatch_to_wtp_resp(wtp_event);
/* TR-Abort.req(RESUME) the Connect transaction */
send_abort(WSP_ABORT_RESUME, sm->connect_handle);
/* Abort(RESUME) all method and push transactions */
abort_methods(sm, WSP_ABORT_RESUME);
/* S-Suspend.ind(RESUME) */
indicate_suspend(sm, WSP_ABORT_RESUME);
/* S-Resume.ind */
new_headers = unpack_new_headers(sm, pdu->u.Resume.headers);
indicate_resume(sm, e->addr_tuple, new_headers);
http_destroy_headers(new_headers);
sm->resume_handle = e->handle;
},
RESUMING)
ROW(CONNECTING_2,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Disconnect,
{
/* TR-Abort.req(DISCONNECT) the Connect transaction */
send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle);
/* Abort(DISCONNECT) all method and push transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(CONNECTING_2,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Suspend && resume_enabled,
{
/* Resume facility enabled */
/* TR-Abort.req(SUSPEND) the Connect transaction */
send_abort(WSP_ABORT_SUSPEND, sm->connect_handle);
/* Abort(SUSPEND) all method and push transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(SUSPEND) */
indicate_suspend(sm, WSP_ABORT_SUSPEND);
},
SUSPENDED)
ROW(CONNECTING_2,
TR_Invoke_Cnf,
1,
{
/* See push state table*/
WSPPushMachine *spm;
spm = find_push_machine(sm, e->handle);
handle_push_event(sm, spm, current_event);
},
CONNECTING_2)
ROW(CONNECTING_2,
TR_Result_Cnf,
e->handle == sm->connect_handle,
{
},
CONNECTED)
ROW(CONNECTING_2,
TR_Result_Cnf,
e->handle != sm->connect_handle,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTING_2)
ROW(CONNECTING_2,
TR_Abort_Ind,
e->handle == sm->connect_handle,
{
/* Abort(DISCONNECT) all method and push transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(abort reason) */
indicate_disconnect(sm, e->abort_code);
},
NULL_SESSION)
/*
* A separate flag tells is the indicator the initiator or the responder.
*/
ROW(CONNECTING_2,
TR_Abort_Ind,
e->handle != sm->connect_handle && e->ir_flag == RESPONDER_INDICATION,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTING_2)
ROW(CONNECTING_2,
TR_Abort_Ind,
e->handle != sm->connect_handle && e->ir_flag == INITIATOR_INDICATION,
{
WSPPushMachine *m;
/* See push state table */
m = find_push_machine(sm, e->handle);
handle_push_event(sm, m, current_event);
},
CONNECTING_2)
/* MISSING: CONNECTED, S-Disconnect.req */
ROW(CONNECTED,
Disconnect_Event,
1,
{
/* Abort(DISCONNECT) all method and push transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(CONNECTED,
S_MethodInvoke_Res,
1,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->server_transaction_id);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTED)
ROW(CONNECTED,
S_MethodResult_Req,
1,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->server_transaction_id);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTED)
ROW(CONNECTED,
S_Push_Req,
1,
{
WSP_PDU *pdu;
pdu = make_push_pdu(current_event);
send_invoke(sm, pdu, current_event, TRANSACTION_CLASS_0);
},
CONNECTED)
ROW(CONNECTED,
S_ConfirmedPush_Req,
1,
{
/* Start new push transaction*/
WSPPushMachine *spm;
spm = push_machine_create(sm, e->server_push_id);
handle_push_event(sm, spm, current_event);
},
CONNECTED)
ROW(CONNECTED,
Suspend_Event,
!resume_enabled,
{
/* Session Resume facility disabled */
/* Abort(SUSPEND) all method and push transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Disconnect.ind(SUSPEND) */
indicate_disconnect(sm, WSP_ABORT_SUSPEND);
},
NULL_SESSION)
ROW(CONNECTED,
Suspend_Event,
resume_enabled,
{
/* Session Resume facility enabled */
/* Abort(SUSPEND) all method and push transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(SUSPEND) */
indicate_suspend(sm, WSP_ABORT_SUSPEND);
},
SUSPENDED)
ROW(CONNECTED,
TR_Invoke_Ind,
e->tcl == 2 && (pdu->type == Get || pdu->type == Post),
{
WSPMethodMachine *msm;
WAPEvent *new_event;
/* Start new method transaction */
msm = method_machine_create(sm, e->handle);
/* Hand off the event to the new method machine */
handle_method_event(sm, msm, current_event, pdu);
/* Release the new method transaction */
new_event = wap_event_create(Release_Event);
handle_method_event(sm, msm, new_event, NULL);
wap_event_destroy(new_event);
},
CONNECTED)
ROW(CONNECTED,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Resume && !resume_enabled,
{
/* Resume facility disabled */
/* TR-Abort.req(DISCONNECT) the TR-Invoke */
send_abort(WSP_ABORT_DISCONNECT, e->handle);
},
CONNECTED)
ROW(CONNECTED,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Resume && resume_enabled,
{
/* Resume facility enabled */
WAPEvent *wtp_event;
List *new_headers;
/* TR-Invoke.res */
wtp_event = wap_event_create(TR_Invoke_Res);
wtp_event->u.TR_Invoke_Res.handle = e->handle;
dispatch_to_wtp_resp(wtp_event);
/* Abort(RESUME) all method and push transactions */
abort_methods(sm, WSP_ABORT_RESUME);
/* S-Suspend.ind(RESUME) */
indicate_suspend(sm, WSP_ABORT_RESUME);
/* S-Resume.ind */
new_headers = unpack_new_headers(sm, pdu->u.Resume.headers);
indicate_resume(sm, e->addr_tuple, new_headers);
http_destroy_headers(new_headers);
sm->resume_handle = e->handle;
},
RESUMING)
ROW(CONNECTED,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Disconnect,
{
/* Abort(DISCONNECT) all method and push transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(CONNECTED,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Suspend && resume_enabled,
{
/* Abort(SUSPEND) all method and push transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(SUSPEND) */
indicate_suspend(sm, WSP_ABORT_SUSPEND);
},
SUSPENDED)
ROW(CONNECTED,
TR_Invoke_Cnf,
1,
{
/* See push state table*/
WSPPushMachine *spm;
spm = find_push_machine(sm, e->handle);
handle_push_event(sm, spm, current_event);
},
CONNECTED)
ROW(CONNECTED,
TR_Result_Cnf,
e->handle != sm->connect_handle,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTED)
/*
* Event TR-Abort.ind has a separate flag telling is the indicator the
* initiator or the responder.
*/
ROW(CONNECTED,
TR_Abort_Ind,
e->handle != sm->connect_handle && e->ir_flag == RESPONDER_INDICATION,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
},
CONNECTED)
ROW(CONNECTED,
TR_Abort_Ind,
e->handle != sm->connect_handle && e->ir_flag == INITIATOR_INDICATION,
{
WSPPushMachine *m;
/* See push state table */
m = find_push_machine(sm, e->handle);
handle_push_event(sm, m, current_event);
},
CONNECTED)
/* MISSING: SUSPENDED, S-Disconnect.req */
ROW(SUSPENDED,
Disconnect_Event,
1,
{
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(SUSPENDED,
TR_Invoke_Ind,
e->tcl == 2 && (pdu->type == Get || pdu->type == Post),
{
/* TR-Abort.req(SUSPEND) the TR-Invoke */
send_abort(WSP_ABORT_SUSPEND, e->handle);
},
SUSPENDED)
ROW(SUSPENDED,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Resume,
{
WAPEvent *wtp_event;
List *new_headers;
/* TR-Invoke.res */
wtp_event = wap_event_create(TR_Invoke_Res);
wtp_event->u.TR_Invoke_Res.handle = e->handle;
dispatch_to_wtp_resp(wtp_event);
/* S-Resume.ind */
new_headers = unpack_new_headers(sm, pdu->u.Resume.headers);
indicate_resume(sm, e->addr_tuple, new_headers);
http_destroy_headers(new_headers);
sm->resume_handle = e->handle;
},
RESUMING)
ROW(SUSPENDED,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Disconnect,
{
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
/* MISSING: RESUMING, S-Disconnect.req */
ROW(RESUMING,
Disconnect_Event,
1,
{
/* TR-Abort.req(DISCONNECT) the Resume transaction */
send_abort(WSP_ABORT_DISCONNECT, sm->resume_handle);
/* Abort(DISCONNECT) all method transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(RESUMING,
S_Resume_Res,
1,
{
WAPEvent *wtp_event;
Octstr *ospdu;
/* Disconnect any other session for the peer address quadruplet */
disconnect_other_sessions(sm);
/* Bind session to new peer address quadruplet */
/* this happens automatically XXX Not true */
/* TR-Result.req(Reply) */
if (e->server_headers == NULL)
e->server_headers = http_create_empty_headers();
ospdu = make_resume_reply_pdu(sm, e->server_headers);
wtp_event = wap_event_create(TR_Result_Req);
wtp_event->u.TR_Result_Req.user_data = ospdu;
wtp_event->u.TR_Result_Req.handle = sm->resume_handle;
dispatch_to_wtp_resp(wtp_event);
/* Release all method transactions in HOLDING state */
release_holding_methods(sm);
},
RESUMING_2)
ROW(RESUMING,
Suspend_Event,
1,
{
/* TR-Abort.req(SUSPEND) the Resume transaction */
send_abort(WSP_ABORT_SUSPEND, sm->resume_handle);
/* Abort(SUSPEND) all method transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(SUSPEND) */
indicate_suspend(sm, WSP_ABORT_SUSPEND);
},
SUSPENDED)
ROW(RESUMING,
TR_Invoke_Ind,
e->tcl == 2 && (pdu->type == Get || pdu->type == Post),
{
/* Start new method transaction (see method state table) */
WSPMethodMachine *msm;
msm = method_machine_create(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
},
RESUMING)
ROW(RESUMING,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Resume,
{
WAPEvent *wtp_event;
List *new_headers;
/* TR-Invoke.res */
wtp_event = wap_event_create(TR_Invoke_Res);
wtp_event->u.TR_Invoke_Res.handle = e->handle;
dispatch_to_wtp_resp(wtp_event);
/* TR-Abort.req(RESUME) the old Resume transaction */
send_abort(WSP_ABORT_RESUME, sm->resume_handle);
/* Abort(RESUME) all method transactions */
abort_methods(sm, WSP_ABORT_RESUME);
/* S-Suspend.ind(RESUME) */
indicate_suspend(sm, WSP_ABORT_RESUME);
/* S-Resume.ind */
new_headers = unpack_new_headers(sm, pdu->u.Resume.headers);
indicate_resume(sm, e->addr_tuple, new_headers);
http_destroy_headers(new_headers);
sm->resume_handle = e->handle;
},
RESUMING)
ROW(RESUMING,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Suspend,
{
/* TR-Abort.req(SUSPEND) the Resume transaction */
send_abort(WSP_ABORT_SUSPEND, sm->resume_handle);
/* Abort(SUSPEND) all method transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(SUSPEND) */
indicate_suspend(sm, WSP_ABORT_SUSPEND);
},
SUSPENDED)
ROW(RESUMING,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Disconnect,
{
/* TR-Abort.req(DISCONNECT) the Resume transaction */
send_abort(WSP_ABORT_DISCONNECT, sm->resume_handle);
/* Abort(DISCONNECT) all method transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(RESUMING,
TR_Abort_Ind,
e->handle == sm->resume_handle,
{
/* Abort(SUSPEND) all method transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(abort reason) */
indicate_suspend(sm, e->abort_code);
},
SUSPENDED)
/* MISSING: RESUMING_2, S-Disconnect.req */
ROW(RESUMING_2,
Disconnect_Event,
1,
{
/* TR-Abort.req(DISCONNECT) the Resume */
send_abort(WSP_ABORT_DISCONNECT, sm->resume_handle);
/* Abort(DISCONNECT) all method and push transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(RESUMING_2,
S_MethodInvoke_Res,
1,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->server_transaction_id);
handle_method_event(sm, msm, current_event, pdu);
},
RESUMING_2)
ROW(RESUMING_2,
S_MethodResult_Req,
1,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->server_transaction_id);
handle_method_event(sm, msm, current_event, pdu);
},
RESUMING_2)
ROW(RESUMING_2,
S_Push_Req,
1,
{
WSP_PDU *pdu;
pdu = make_push_pdu(current_event);
send_invoke(sm, pdu, current_event, TRANSACTION_CLASS_0);
},
RESUMING_2)
ROW(RESUMING_2,
S_ConfirmedPush_Req,
1,
{
/* Start new push transaction*/
WSPPushMachine *spm;
spm = push_machine_create(sm, e->server_push_id);
handle_push_event(sm, spm, current_event);
},
RESUMING_2)
ROW(RESUMING_2,
Suspend_Event,
1,
{
/* TR-Abort.req(SUSPEND) the Resume transaction */
send_abort(WSP_ABORT_SUSPEND, sm->resume_handle);
/* Abort(SUSPEND) all method and push transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(SUSPEND) */
indicate_suspend(sm, WSP_ABORT_SUSPEND);
},
SUSPENDED)
ROW(RESUMING_2,
TR_Invoke_Ind,
e->tcl == 2 && (pdu->type == Get || pdu->type == Post),
{
WSPMethodMachine *msm;
WAPEvent *new_event;
/* Start new method transaction (see method state table) */
msm = method_machine_create(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
/* Release the new method transaction */
new_event = wap_event_create(Release_Event);
handle_method_event(sm, msm, new_event, NULL);
wap_event_destroy(new_event);
},
RESUMING_2)
ROW(RESUMING_2,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Resume,
{
WAPEvent *wtp_event;
List *new_headers;
/* TR-Invoke.res */
wtp_event = wap_event_create(TR_Invoke_Res);
wtp_event->u.TR_Invoke_Res.handle = e->handle;
dispatch_to_wtp_resp(wtp_event);
/* TR-Abort.req(RESUME) the old Resume transaction*/
send_abort(WSP_ABORT_RESUME, sm->resume_handle);
/* Abort(RESUME) all method and push transactions */
abort_methods(sm, WSP_ABORT_RESUME);
/* S-Suspend.ind(RESUME) */
indicate_suspend(sm, WSP_ABORT_RESUME);
/* S-Resume.ind */
new_headers = unpack_new_headers(sm, pdu->u.Resume.headers);
indicate_resume(sm, e->addr_tuple, new_headers);
http_destroy_headers(new_headers);
sm->resume_handle = e->handle;
},
RESUMING)
ROW(RESUMING_2,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Suspend,
{
/* TR-Abort.req(SUSPEND) the Resume transaction */
send_abort(WSP_ABORT_SUSPEND, sm->resume_handle);
/* Abort(SUSPEND) all method and push transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(SUSPEND) */
indicate_suspend(sm, WSP_ABORT_SUSPEND);
},
SUSPENDED)
ROW(RESUMING_2,
TR_Invoke_Ind,
e->tcl == 0 && pdu->type == Disconnect,
{
/* TR-Abort.req(DISCONNECT) the Resume */
send_abort(WSP_ABORT_DISCONNECT, sm->resume_handle);
/* Abort(DISCONNECT) all method and push transactions */
abort_methods(sm, WSP_ABORT_DISCONNECT);
/* S-Disconnect.ind(DISCONNECT) */
indicate_disconnect(sm, WSP_ABORT_DISCONNECT);
},
NULL_SESSION)
ROW(RESUMING_2,
TR_Invoke_Cnf,
1,
{
/* See push state table*/
WSPPushMachine *spm;
spm = find_push_machine(sm, e->handle);
handle_push_event(sm, spm, current_event);
},
RESUMING_2)
ROW(RESUMING_2,
TR_Result_Cnf,
e->handle == sm->resume_handle,
{
},
CONNECTED)
ROW(RESUMING_2,
TR_Result_Cnf,
e->handle != sm->resume_handle,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
},
RESUMING_2)
ROW(RESUMING_2,
TR_Abort_Ind,
e->handle == sm->resume_handle,
{
/* Abort(SUSPEND) all method and push transactions */
abort_methods(sm, WSP_ABORT_SUSPEND);
/* S-Suspend.ind(abort reason) */
indicate_suspend(sm, e->abort_code);
},
SUSPENDED)
/*
* A separate flag tells is the indicator the initiator or the responder
*/
ROW(RESUMING_2,
TR_Abort_Ind,
e->handle != sm->resume_handle && e->ir_flag == RESPONDER_INDICATION,
{
WSPMethodMachine *msm;
/* See method state table */
msm = find_method_machine(sm, e->handle);
handle_method_event(sm, msm, current_event, pdu);
},
RESUMING_2)
ROW(CONNECTING_2,
TR_Abort_Ind,
e->handle != sm->connect_handle && e->ir_flag == INITIATOR_INDICATION,
{
WSPPushMachine *m;
/* See push state table */
m = find_push_machine(sm, e->handle);
handle_push_event(sm, m, current_event);
},
CONNECTING_2)
#undef ROW
#undef STATE_NAME
gateway-1.4.3/wap/wtls_state-decl.h 0000644 0001750 0001750 00000076647 11132672003 016273 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* Macro calls to generate rows of the state table. See the documentation for
* guidance how to use and update these.
*
* by Nick Clarey
*/
STATE_NAME(NULL_STATE)
STATE_NAME(CREATING)
STATE_NAME(CREATED)
STATE_NAME(EXCHANGE)
STATE_NAME(COMMIT)
STATE_NAME(OPENING)
STATE_NAME(OPEN)
/* If the packet is a ClientHello */
/* We only include this case in state NULL; the others are handled by the
wtls_find_or_create function */
ROW(NULL_STATE,
T_Unitdata_Ind,
1,
{
/* The Wap event we have to dispatch */
WAPEvent *res;
wtls_Payload* tempPayload;
wtls_PDU* clientHelloPDU;
CipherSuite* ciphersuite;
int randomCounter;
tempPayload = (wtls_Payload*) gwlist_search (event->u.T_Unitdata_Ind.pdu_list,
(void*) client_hello,
match_handshake_type);
clientHelloPDU = wtls_pdu_unpack(tempPayload,wtls_machine);
/* Store the client's random value - use pack for simplicity */
wtls_machine->client_random = octstr_create("");
randomCounter = pack_int32(wtls_machine->client_random,0,
clientHelloPDU->u.handshake.client_hello->random->gmt_unix_time);
octstr_insert(wtls_machine->client_random,
clientHelloPDU->u.handshake.client_hello->random->random_bytes,
randomCounter);
/* Generate a SEC_Create_Res event, and pass it back into the queue */
res = wap_event_create(SEC_Create_Res);
res->u.SEC_Create_Res.addr_tuple =
wap_addr_tuple_duplicate(event->u.T_Unitdata_Ind.addr_tuple);
/* Select the ciphersuite from the supplied list */
ciphersuite = wtls_choose_ciphersuite(clientHelloPDU->u.handshake.client_hello->ciphersuites);
/* Set the relevant values in the wtls_machine and PDU structure */
wtls_machine->bulk_cipher_algorithm = ciphersuite->bulk_cipher_algo;
wtls_machine->mac_algorithm = ciphersuite->mac_algo;
res->u.SEC_Create_Res.bulk_cipher_algo = ciphersuite->bulk_cipher_algo;
res->u.SEC_Create_Res.mac_algo = ciphersuite->mac_algo;
res->u.SEC_Create_Res.client_key_id =
wtls_choose_clientkeyid(clientHelloPDU->u.handshake.client_hello->client_key_ids);
/* Set the sequence number mode in both the machine and the outgoing packet */
res->u.SEC_Create_Res.snmode = wtls_choose_snmode(clientHelloPDU->u.handshake.client_hello->snmode);
wtls_machine->sequence_number_mode = res->u.SEC_Create_Res.snmode;
/* Set the key refresh mode in both the machine and the outgoing packet */
res->u.SEC_Create_Res.krefresh = wtls_choose_krefresh(clientHelloPDU->u.handshake.client_hello->krefresh);
wtls_machine->key_refresh = res->u.SEC_Create_Res.krefresh;
/* Keep the data so we can send it back in EXCHANGE */
// temporary - needs to delete old one if exists !
//wtls_machine->handshake_data = octstr_create("");
octstr_append(wtls_machine->handshake_data, tempPayload->data);
debug("wtls:handle_event", 0,"Dispatching SEC_Create_Res event");
wtls_dispatch_event(res);
},
CREATING)
/* Creating State */
/* Termination */
ROW(CREATING,
SEC_Terminate_Req,
1,
{
/* Send off a T_Unitdata_Req containing an alert as specified */
send_alert(event->u.SEC_Terminate_Req.alert_level,
event->u.SEC_Terminate_Req.alert_desc,
wtls_machine);
},
NULL_STATE)
/* Exception */
ROW(CREATING,
SEC_Exception_Req,
1,
{
/* Send off a T_Unitdata_Req containing an exception as specified */
send_alert(event->u.SEC_Exception_Req.alert_level,
event->u.SEC_Exception_Req.alert_desc, wtls_machine);
},
CREATING)
/* Create Response - create a buffer with a "ServerHello" and possibly a Certificate or something else */
ROW(CREATING,
SEC_Create_Res,
1,
{
WAPEvent *req;
wtls_PDU* serverHelloPDU;
Random* tempRandom;
int randomCounter = 0;
/* Our serverHello */
serverHelloPDU = wtls_pdu_create(Handshake_PDU);
serverHelloPDU->u.handshake.msg_type = server_hello;
serverHelloPDU->u.handshake.server_hello = (ServerHello*) gw_malloc(sizeof(ServerHello));
/* Set our server version */
serverHelloPDU->u.handshake.server_hello->serverversion = 1;
/* Get a suitably random number - store it in both the machine structure and outgoing PDU */
tempRandom = wtls_get_random();
wtls_machine->server_random = octstr_create("");
randomCounter = pack_int32(wtls_machine->server_random,0,tempRandom->gmt_unix_time);
octstr_insert(wtls_machine->server_random,tempRandom->random_bytes,octstr_len(wtls_machine->server_random));
serverHelloPDU->u.handshake.server_hello->random = tempRandom;
/* At the moment, we don't support session caching, so tell them to forget about caching us */
serverHelloPDU->u.handshake.server_hello->session_id = octstr_create("");
/* We need to select an appropriate mechanism here from the ones listed */
serverHelloPDU->u.handshake.server_hello->client_key_id = event->u.SEC_Create_Res.client_key_id;
/* Get our ciphersuite details */
serverHelloPDU->u.handshake.server_hello->ciphersuite = (CipherSuite*) gw_malloc(sizeof(CipherSuite));
serverHelloPDU->u.handshake.server_hello->ciphersuite->bulk_cipher_algo = event->u.SEC_Create_Res.bulk_cipher_algo;
serverHelloPDU->u.handshake.server_hello->ciphersuite->mac_algo = event->u.SEC_Create_Res.mac_algo;
serverHelloPDU->u.handshake.server_hello->comp_method = null_comp;
/* We need to confirm the client's choice, or if they haven't specified one, select
one ourselves */
serverHelloPDU->u.handshake.server_hello->snmode = event->u.SEC_Create_Res.snmode;
/* We need to either confirm the client's choice of key refresh rate, or choose a lower rate */
serverHelloPDU->u.handshake.server_hello->krefresh = event->u.SEC_Create_Res.krefresh;
/* Add the PDUsto the server's outgoing list */
add_pdu(wtls_machine, serverHelloPDU);
/* Generate and dispatch a SEC_Exchange_Req or maybe a SEC_Commit_Req */
req = wap_event_create(SEC_Exchange_Req);
req->u.SEC_Exchange_Req.addr_tuple =
wap_addr_tuple_duplicate(event->u.T_Unitdata_Ind.addr_tuple);
wtls_dispatch_event(req);
debug("wtls: handle_event", 0,"Dispatching SEC_Exchange_Req event");
},
CREATED)
/* Created State */
/* Exchange Request - Full Handshake will be performed */
ROW(CREATED,
SEC_Exchange_Req,
1,
{
wtls_PDU* serverKeyXchgPDU;
wtls_PDU* serverHelloDonePDU;
/* Assert that the PDU list is valid */
gw_assert(wtls_machine->packet_to_send != NULL);
/* We'll also need a Server Key Exchange message */
serverKeyXchgPDU = wtls_pdu_create(Handshake_PDU);
serverKeyXchgPDU->u.handshake.msg_type = server_key_exchange;
serverKeyXchgPDU->u.handshake.server_key_exchange = (ServerKeyExchange*) gw_malloc(sizeof(ServerKeyExchange));
serverKeyXchgPDU->u.handshake.server_key_exchange->param_spec = NULL;
/* Allocate memory for the RSA component */
debug("wtls: ", 0,"Going to get the RSA public key...");
serverKeyXchgPDU->u.handshake.server_key_exchange->rsa_params = wtls_get_rsapublickey();
debug("wtls: ", 0,"...got it.");
add_pdu(wtls_machine, serverKeyXchgPDU);
debug("wtls: ", 0,"in CREATED - just added pdu...");
/* Add some more PDUs to the List - potentially a ServerKeyExchange,
a CertificateRequest and a ServerHelloDone */
/* Just a ServerHelloDone for now */
serverHelloDonePDU = wtls_pdu_create(Handshake_PDU);
serverHelloDonePDU->u.handshake.msg_type = server_hello_done;
add_pdu(wtls_machine, serverHelloDonePDU);
/* Translate the buffer and address details into a T_Unitdata_Req
* and send it winging it's way across the network */
send_queuedpdus(wtls_machine);
},
EXCHANGE)
/* Commit Request - Abbreviated Handshake will be performed */
ROW(CREATED,
SEC_Commit_Req,
1,
{
/* Assert that the PDU list is valid */
/* Add some more PDUs to the List - a ChangeCipherSpec and a Finished */
/* Translate the buffer and address details into a T_Unitdata_Req */
/* And send it winging it's way across the network */
},
COMMIT)
/* Terminate Request */
ROW(CREATED,
SEC_Terminate_Req,
1,
{
/* Send off a T_Unitdata_Req containing an alert as specified */
send_alert(event->u.SEC_Terminate_Req.alert_level,
event->u.SEC_Terminate_Req.alert_desc, wtls_machine);
},
NULL_STATE)
/* Exception Request */
ROW(CREATED,
SEC_Exception_Req,
1,
{
/* Send off a T_Unitdata_Req containing an exception as specified */
send_alert(event->u.SEC_Exception_Req.alert_level,
event->u.SEC_Exception_Req.alert_desc, wtls_machine);
},
CREATED)
/* Exchange State */
/* Unitdata arrival - identical ClientHello record */
ROW(EXCHANGE,
T_Unitdata_Ind,
clienthellos_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1,
{
/* It appears as though someone has sent us an identical ClientHello to the last one */
/* Make ourselves a T_Unitdata_Req with the last_transmitted_packet */
/* And send it on it's merry */
},
EXCHANGE)
/* Unitdata arrival - non-identical ClientHello record */
//ROW(EXCHANGE,
// T_Unitdata_Ind,
// clienthellos_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) != 1,
// {
/* So, this one's different. They must have changed their mind about something, so try a CREATING again */
/* Do the necessary SEC_Create_Ind stuff */
// },
// CREATING)
/* Unitdata arrival - good packet */
ROW(EXCHANGE,
T_Unitdata_Ind,
1,
{
RSAPublicKey *public_key = NULL;
Octstr* key_block;
Octstr* final_client_write_enc_key = NULL;
Octstr* final_server_write_enc_key = NULL;
Octstr* final_client_write_IV = NULL;
Octstr* final_server_write_IV = NULL;
Octstr* emptySecret = NULL;
Octstr* checking_data = NULL;
// packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
// packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
// packet_contains_optional_stuff (event->u.T_Unitdata_Ind.pdu_list) == 1,
/* The Wap PDUs we have to dispatch */
wtls_PDU* changeCipherSpecPDU;
wtls_PDU* finishedPDU;
/* The PDUs we have to process */
wtls_Payload* tempPayload;
wtls_PDU* clientKeyXchgPDU;
wtls_PDU* changeCipherSpec_incoming_PDU;
wtls_PDU* finished_incoming_PDU;
/* For decrypting/encrypting data */
Octstr* concatenatedRandoms=0;
Octstr* encryptedData=0;
Octstr* decryptedData=0;
Octstr* labelVerify=0;
Octstr* labelMaster=0;
/* Process the incoming event : ClientKeyExchange*/
tempPayload = (wtls_Payload*) gwlist_search (event->u.T_Unitdata_Ind.pdu_list,
(void*) client_key_exchange,
match_handshake_type);
/* Keep the data so we can send it back */
octstr_insert(wtls_machine->handshake_data, tempPayload->data,
octstr_len(wtls_machine->handshake_data));
clientKeyXchgPDU = wtls_pdu_unpack(tempPayload,wtls_machine);
wtls_pdu_dump(clientKeyXchgPDU,0);
/* Decrypt the client key exchange PDU */
encryptedData = clientKeyXchgPDU->u.handshake.client_key_exchange->rsa_params->encrypted_secret;
decryptedData = wtls_decrypt_rsa(encryptedData);
public_key = wtls_get_rsapublickey();
pack_int16(decryptedData, octstr_len(decryptedData), octstr_len(public_key->rsa_exponent));
octstr_insert(decryptedData, public_key->rsa_exponent, octstr_len(decryptedData));
pack_int16(decryptedData, octstr_len(decryptedData), octstr_len(public_key->rsa_modulus));
octstr_insert(decryptedData, public_key->rsa_modulus, octstr_len(decryptedData));
/* Concatenate our random data */
concatenatedRandoms = octstr_cat(wtls_machine->client_random,
wtls_machine->server_random);
/* Generate our master secret */
labelMaster = octstr_create("master secret");
wtls_machine->master_secret = wtls_calculate_prf(decryptedData, labelMaster,
concatenatedRandoms,20, wtls_machine );
octstr_destroy(labelMaster);
labelMaster = NULL;
/* calculate the key blocks */
calculate_server_key_block(wtls_machine);
calculate_client_key_block(wtls_machine);
/* Process the incoming event : ChangeCipherSpec*/
tempPayload = (wtls_Payload*) gwlist_search (event->u.T_Unitdata_Ind.pdu_list,
(void*) ChangeCipher_PDU,
match_pdu_type);
changeCipherSpec_incoming_PDU = wtls_pdu_unpack(tempPayload, wtls_machine);
if(changeCipherSpec_incoming_PDU->u.cc.change == 1) {
debug("wtls", 0,"Need to decrypt the PDUs from now on...");
wtls_machine->encrypted = 1;
wtls_decrypt_pdu_list(wtls_machine, event->u.T_Unitdata_Ind.pdu_list);
}
octstr_dump(wtls_machine->client_write_MAC_secret,0);
wtls_pdu_dump(changeCipherSpec_incoming_PDU,0);
/* Process the incoming event : Finished*/
tempPayload = (wtls_Payload*) gwlist_search (event->u.T_Unitdata_Ind.pdu_list,
(void*) finished,
match_handshake_type);
if(tempPayload == NULL)
debug("wtls", 0, "null finished !!!");
finished_incoming_PDU = wtls_pdu_unpack(tempPayload,wtls_machine);
debug("wtls", 0, "Client Finished PDU:");
wtls_pdu_dump(finished_incoming_PDU,0);
/* Check the verify_data */
labelVerify = octstr_create("client finished");
checking_data = wtls_calculate_prf(wtls_machine->master_secret, labelVerify,
(Octstr *)wtls_hash(wtls_machine->handshake_data, wtls_machine),
12, wtls_machine);
octstr_destroy(labelVerify);
labelVerify = NULL;
if(octstr_compare(finished_incoming_PDU->u.handshake.finished->verify_data, checking_data)==0) {
debug("wtls", 0, "DATA VERIFICATION OK");
}
/* Keep the data so we can send it back in the next message */
/*octstr_insert(wtls_machine->handshake_data, tempPayload->data,
octstr_len(wtls_machine->handshake_data));
*/
// temporary fix
octstr_truncate(tempPayload->data, 15);
octstr_insert(wtls_machine->handshake_data, tempPayload->data,
octstr_len(wtls_machine->handshake_data));
/* Create a new PDU List containing a ChangeCipherSpec and a Finished */
changeCipherSpecPDU = wtls_pdu_create(ChangeCipher_PDU);
changeCipherSpecPDU->u.cc.change = 1;
/* Generate our verify data */
finishedPDU = wtls_pdu_create(Handshake_PDU);
finishedPDU->u.handshake.msg_type = finished;
finishedPDU->cipher = 1;
finishedPDU->u.handshake.finished = gw_malloc(sizeof(Finished));
labelVerify = octstr_create("server finished");
finishedPDU->u.handshake.finished->verify_data = wtls_calculate_prf(wtls_machine->master_secret,
labelVerify,(Octstr *)wtls_hash(wtls_machine->handshake_data, wtls_machine),
12,wtls_machine);
/* Reset the accumulated Handshake data */
octstr_destroy(wtls_machine->handshake_data);
wtls_machine->handshake_data = octstr_create("");
octstr_destroy(labelVerify);
labelVerify = NULL;
/* Add the pdus to our list */
add_pdu(wtls_machine, changeCipherSpecPDU);
add_pdu(wtls_machine, finishedPDU);
/* Send it off */
send_queuedpdus(wtls_machine);
/* reset the seq_num */
wtls_machine->server_seq_num = 0;
},
OPENING)
/* Unitdata arrival - critical/fatal alert */
ROW(EXCHANGE,
T_Unitdata_Ind,
is_critical_alert(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Do the necessary SEC_Terminate_Ind stuff */
/* And we're dead :-< */
},
NULL_STATE)
/* Unitdata arrival - warning alert */
ROW(EXCHANGE,
T_Unitdata_Ind,
is_warning_alert(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Do the necessary SEC_Exception_Ind stuff */
},
EXCHANGE)
/* Terminate */
ROW(EXCHANGE,
SEC_Terminate_Req,
1,
{
/* Send off a T_Unitdata_Req containing an alert as specified */
send_alert(event->u.SEC_Terminate_Req.alert_level,
event->u.SEC_Terminate_Req.alert_desc, wtls_machine);
},
NULL_STATE)
/* Exception */
ROW(EXCHANGE,
SEC_Exception_Req,
1,
{
/* Send off a T_Unitdata_Req containing an exception as specified */
send_alert(event->u.SEC_Exception_Req.alert_level,
event->u.SEC_Exception_Req.alert_desc, wtls_machine);
},
EXCHANGE)
/* Commit State */
/* Unitdata arrival - identical ClientHello record */
ROW(COMMIT,
T_Unitdata_Ind,
clienthellos_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1,
{
/* It appears as though someone has sent us an identical ClientHello to the last one */
/* Make ourselves a T_Unitdata_Req with the last_transmitted_packet */
/* And send it on it's merry way */
},
COMMIT)
/* Unitdata arrival - non-identical ClientHello record */
ROW(COMMIT,
T_Unitdata_Ind,
clienthellos_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) != 1,
{
/* So, this one's different. They must have changed their mind about something, so try a CREATING again */
/* Do the necessary SEC_Create_Ind stuff */
},
CREATING)
/* Unitdata arrival - good packet with ChangeCipherSpec and Finished */
ROW(COMMIT,
T_Unitdata_Ind,
packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
packet_contains_userdata (event->u.T_Unitdata_Ind.pdu_list) != 1,
{
/* Create ourselves a SEC_Commit_Cnf packet to send off */
/* Send it off */
},
OPEN)
/* Unitdata arrival - good packet with ChangeCipherSpec, Finished and UD */
ROW(COMMIT,
T_Unitdata_Ind,
packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
packet_contains_userdata (event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Create a SEC_Commit_Cnf packet to send off */
/* Send it off */
/* Relay the contents of the packets up to the WTP or WSP layers,
depending on the destination port */
},
OPEN)
/* Unitdata arrival - critical/fatal alert */
ROW(COMMIT,
T_Unitdata_Ind,
is_critical_alert(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Do the necessary SEC_Terminate_Ind stuff */
/* And we're dead :-< */
},
NULL_STATE)
/* Unitdata arrival - warning alert */
ROW(COMMIT,
T_Unitdata_Ind,
is_warning_alert(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Do the necessary SEC_Exception_Ind stuff */
},
COMMIT)
/* Terminate */
ROW(COMMIT,
SEC_Terminate_Req,
1,
{
/* Send off a T_Unitdata_Req containing an alert as specified */
send_alert(event->u.SEC_Terminate_Req.alert_level,
event->u.SEC_Terminate_Req.alert_desc, wtls_machine);
},
NULL_STATE)
/* Exception */
ROW(COMMIT,
SEC_Exception_Req,
1,
{
/* Send off a T_Unitdata_Req containing an exception as specified */
send_alert(event->u.SEC_Exception_Req.alert_level,
event->u.SEC_Exception_Req.alert_desc, wtls_machine);
},
COMMIT)
/* Opening State */
/* Create Request */
ROW(OPENING,
SEC_Create_Request_Req,
1,
{
/* Send off a T_Unitdata_Req containing a HelloRequest */
},
OPENING)
/* Send out UnitData */
ROW(OPENING,
SEC_Unitdata_Req,
1,
{
/* Apply the negotiated security "stuff" to the received packet */
/* Send out the packet to the destination port/address requested */
},
OPENING)
/* Unitdata received - ClientHello */
//ROW(OPENING,
// T_Unitdata_Ind,
// packet_contains_clienthello (event->u.T_Unitdata_Ind.pdu_list) == 0,
// {
///* Hmm, they're obviously not happy with something we discussed, so let's head back to creating */
///* Do the necessary SEC_Create_Ind stuff */
//},
// CREATING)
/* Unitdata received */
ROW(OPENING,
T_Unitdata_Ind,
packet_contains_userdata(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
wtls_Payload* tempPayload;
wtls_PDU* ApplicationPDU;
tempPayload = (wtls_Payload*) gwlist_search (event->u.T_Unitdata_Ind.pdu_list,
(void*) Application_PDU,
match_pdu_type);
if(tempPayload == NULL)
debug("wtls", 0, "no App PDU found in list !!!");
debug("wtls",0, "PDU type: %d", tempPayload->type);
octstr_dump(tempPayload->data,0);
ApplicationPDU = wtls_pdu_unpack(tempPayload, wtls_machine);
wtls_pdu_dump(ApplicationPDU,0);
/* Apply the negotiated decryption/decoding/MAC check to the received data */
/* Take the userdata and pass it on up to the WTP/WSP, depending on the destination port */
/* calculate the padding length */
/*
contentLength = octstr_len(bufferCopy);
macSize = hash_table[wtls_machine->mac_algorithm].mac_size;
blockLength = bulk_table[wtls_machine->bulk_cipher_algorithm].block_size;
paddingLength = (contentLength + macSize + 1) % (blockLength);
*/
/* get the MAC */
},
OPEN)
/* Unitdata arrival - Certificate, ClientKeyExchange ... Finished */
ROW(OPENING,
T_Unitdata_Ind,
certificates_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1 &&
clientkeyexchanges_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1 &&
certifcateverifys_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1 &&
changecipherspecs_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1 &&
finisheds_are_indentical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1,
{
/* It appears as though someone has sent us an identical ClientHello to the last one */
/* Make ourselves a T_Unitdata_Req with the last_transmitted_packet */
/* And send it on it's merry way */
},
OPENING)
/* Unitdata arrival - critical/fatal alert */
ROW(OPENING,
T_Unitdata_Ind,
is_critical_alert(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Do the necessary SEC_Terminate_Ind stuff */
/* And we're dead :-< */
},
NULL_STATE)
/* Unitdata arrival - warning alert */
ROW(OPENING,
T_Unitdata_Ind,
is_warning_alert(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Do the necessary SEC_Exception_Ind stuff */
},
OPENING)
/* Terminate */
ROW(OPENING,
SEC_Terminate_Req,
1,
{
/* Send off a T_Unitdata_Req containing an alert as specified */
send_alert(event->u.SEC_Terminate_Req.alert_level,
event->u.SEC_Terminate_Req.alert_desc, wtls_machine);
},
NULL_STATE)
/* Exception */
ROW(OPENING,
SEC_Exception_Req,
1,
{
/* Send off a T_Unitdata_Req containing an exception as specified */
send_alert(event->u.SEC_Exception_Req.alert_level,
event->u.SEC_Exception_Req.alert_desc, wtls_machine);
},
OPENING)
/* Open State */
/* Create Request */
ROW(OPEN,
SEC_Create_Request_Req,
1,
{
/* Send off a T_Unitdata_Req with a HelloRequest */
},
OPEN)
/* Send out UnitData */
ROW(OPEN,
SEC_Unitdata_Req,
1,
{
/* Apply the negotiated security "stuff" to the received packet */
/* Send out the packet to the destination port/address requested */
},
OPEN)
/* Unitdata received - ClientHello */
ROW(OPEN,
T_Unitdata_Ind,
packet_contains_clienthello (event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Hmm, they're obviously not happy with something we discussed, so let's head back to creating */
/* Do the necessary SEC_Create_Ind stuff */
},
CREATING)
/* Unitdata received */
ROW(OPEN,
T_Unitdata_Ind,
packet_contains_userdata(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Apply the negotiated decryption/decoding/MAC check to the received data */
/* Take the userdata and pass it on up to the WTP/WSP, depending on the destination port */
},
OPEN)
/* Unitdata arrival - ChangeCipherSpec, Finished */
ROW(OPEN,
T_Unitdata_Ind,
packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
packet_contains_userdata(event->u.T_Unitdata_Ind.pdu_list) != 1 &&
finisheds_are_indentical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1,
{
/* Just send out a T_Unitdata_Req with an Alert(duplicate_finished_received) */
},
OPEN)
/* Unitdata arrival - ChangeCipherSpec, Finished and UD */
ROW(OPEN,
T_Unitdata_Ind,
packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) == 1 &&
packet_contains_userdata(event->u.T_Unitdata_Ind.pdu_list) == 1 &&
finisheds_are_indentical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1,
{
/* Apply the negotiated decryption/decoding/MAC check to the received data */
/* Take the userdata and pass it on up to the WTP/WSP, depending on the destination port */
/* Send out a T_Unitdata_Req with an Alert(duplicate_finished_received) */
},
OPEN)
/* Unitdata arrival - critical/fatal alert */
ROW(OPEN,
T_Unitdata_Ind,
is_critical_alert(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Do the necessary SEC_Terminate_Ind stuff */
/* And we're dead :-< */
},
NULL_STATE)
/* Unitdata arrival - warning alert */
ROW(OPEN,
T_Unitdata_Ind,
is_warning_alert(event->u.T_Unitdata_Ind.pdu_list) == 1,
{
/* Do the necessary SEC_Terminate_Ind stuff */
},
OPEN)
/* Terminate */
ROW(OPEN,
SEC_Terminate_Req,
1,
{
/* Send off a T_Unitdata_Req containing an alert as specified */
send_alert(event->u.SEC_Terminate_Req.alert_level,
event->u.SEC_Terminate_Req.alert_desc, wtls_machine);
},
NULL_STATE)
/* Exception */
ROW(OPEN,
SEC_Exception_Req,
1,
{
/* Send off a T_Unitdata_Req containing an exception as specified */
send_alert(event->u.SEC_Exception_Req.alert_level,
event->u.SEC_Exception_Req.alert_desc, wtls_machine);
},
OPEN)
#undef ROW
#undef STATE_NAME
gateway-1.4.3/wap/wtp.c 0000644 0001750 0001750 00000034460 11132672003 013765 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp.c - WTP common functions implementation
*
* Aarno Syvnen
* Lars Wirzenius
*/
#include "wtp.h"
#include "wap_events.h"
#include "wtp_pdu.h"
/*****************************************************************************
*
* Prototypes of internal functions:
*
* Parse a datagram event (T-DUnitdata.ind) to create a corresponding
* WTPEvents list object. Also check that the datagram is syntactically
* valid. Return a pointer to the event structure that has been created.
* This will be a RcvError packet if there was a problem unpacking the
* datagram.
*/
static WAPEvent *unpack_wdp_datagram_real(WAPEvent *datagram);
static int deduce_tid(Octstr *user_data);
static int concatenated_message(Octstr *user_data);
static int truncated_datagram(WAPEvent *event);
static WAPEvent *unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
static WAPEvent *unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
static WAPEvent *unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
static WAPEvent *pack_error(WAPEvent *datagram);
/******************************************************************************
*
* EXTERNAL FUNCTIONS:
*
* Handles a possible concatenated message. Creates a list of wap events.
*/
List *wtp_unpack_wdp_datagram(WAPEvent *datagram)
{
List *events = NULL;
WAPEvent *event = NULL;
WAPEvent *subdgram = NULL;
Octstr *data = NULL;
long pdu_len;
gw_assert(datagram->type == T_DUnitdata_Ind);
events = gwlist_create();
if (concatenated_message(datagram->u.T_DUnitdata_Ind.user_data)) {
data = octstr_duplicate(datagram->u.T_DUnitdata_Ind.user_data);
octstr_delete(data, 0, 1);
while (octstr_len(data) != 0) {
if (octstr_get_bits(data, 0, 1) == 0) {
pdu_len = octstr_get_char(data, 0);
octstr_delete(data, 0, 1);
} else {
pdu_len = octstr_get_bits(data, 1, 15);
octstr_delete(data, 0, 2);
}
subdgram = wap_event_duplicate(datagram);
octstr_destroy(subdgram->u.T_DUnitdata_Ind.user_data);
subdgram->u.T_DUnitdata_Ind.user_data = octstr_copy(data, 0, pdu_len);
wap_event_assert(subdgram);
if ((event = unpack_wdp_datagram_real(subdgram)) != NULL) {
wap_event_assert(event);
gwlist_append(events, event);
}
octstr_delete(data, 0, pdu_len);
wap_event_destroy(subdgram);
}
octstr_destroy(data);
} else if ((event = unpack_wdp_datagram_real(datagram)) != NULL) {
wap_event_assert(event);
gwlist_append(events, event);
} else {
warning(0, "WTP: Dropping unhandled datagram data:");
octstr_dump(datagram->u.T_DUnitdata_Ind.user_data, 0, GW_WARNING);
}
return events;
}
/*
* Responder set the first bit of the tid field. If we get a packet from the
* responder, we are the initiator and vice versa.
*
* Return 1, when the event is for responder, 0 when it is for initiator and
* -1 when error.
*/
int wtp_event_is_for_responder(WAPEvent *event)
{
switch(event->type){
case RcvInvoke:
return event->u.RcvInvoke.tid < INITIATOR_TID_LIMIT;
case RcvSegInvoke:
return event->u.RcvSegInvoke.tid < INITIATOR_TID_LIMIT;
case RcvResult:
return event->u.RcvResult.tid < INITIATOR_TID_LIMIT;
case RcvAck:
return event->u.RcvAck.tid < INITIATOR_TID_LIMIT;
case RcvNegativeAck:
return event->u.RcvNegativeAck.tid < INITIATOR_TID_LIMIT;
case RcvAbort:
return event->u.RcvAbort.tid < INITIATOR_TID_LIMIT;
case RcvErrorPDU:
return event->u.RcvErrorPDU.tid < INITIATOR_TID_LIMIT;
default:
error(1, "Received an erroneous PDU corresponding an event");
wap_event_dump(event);
return -1;
}
}
/*****************************************************************************
*
* INTERNAL FUNCTIONS:
*
* If pdu was truncated, tid cannot be trusted. We ignore this message.
*/
static int truncated_datagram(WAPEvent *dgram)
{
gw_assert(dgram->type == T_DUnitdata_Ind);
if (octstr_len(dgram->u.T_DUnitdata_Ind.user_data) < 3) {
debug("wap.wtp", 0, "A too short PDU received");
wap_event_dump(dgram);
return 1;
} else
return 0;
}
static WAPEvent *unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
{
WAPEvent *event;
event = wap_event_create(RcvInvoke);
event->u.RcvInvoke.user_data =
octstr_duplicate(pdu->u.Invoke.user_data);
event->u.RcvInvoke.tcl = pdu->u.Invoke.class;
event->u.RcvInvoke.tid = pdu->u.Invoke.tid;
event->u.RcvInvoke.tid_new = pdu->u.Invoke.tidnew;
event->u.RcvInvoke.rid = pdu->u.Invoke.rid;
event->u.RcvInvoke.up_flag = pdu->u.Invoke.uack;
event->u.RcvInvoke.no_cache_supported = 0;
event->u.RcvInvoke.version = pdu->u.Invoke.version;
event->u.RcvInvoke.gtr = pdu->u.Invoke.gtr;
event->u.RcvInvoke.ttr = pdu->u.Invoke.ttr;
event->u.RcvInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
return event;
}
static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
{
WAPEvent *event;
event = wap_event_create(RcvSegInvoke);
event->u.RcvSegInvoke.user_data =
octstr_duplicate(pdu->u.Segmented_invoke.user_data);
event->u.RcvSegInvoke.tid = pdu->u.Segmented_invoke.tid;
event->u.RcvSegInvoke.rid = pdu->u.Segmented_invoke.rid;
event->u.RcvSegInvoke.no_cache_supported = 0;
event->u.RcvSegInvoke.gtr = pdu->u.Segmented_invoke.gtr;
event->u.RcvSegInvoke.ttr = pdu->u.Segmented_invoke.ttr;
event->u.RcvSegInvoke.psn = pdu->u.Segmented_invoke.psn;
event->u.RcvSegInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
return event;
}
static WAPEvent *unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
{
WAPEvent *event;
event = wap_event_create(RcvResult);
event->u.RcvResult.user_data =
octstr_duplicate(pdu->u.Result.user_data);
event->u.RcvResult.tid = pdu->u.Result.tid;
event->u.RcvResult.rid = pdu->u.Result.rid;
event->u.RcvResult.gtr = pdu->u.Result.gtr;
event->u.RcvResult.ttr = pdu->u.Result.ttr;
event->u.RcvResult.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
return event;
}
static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
{
WAPEvent *event;
WTP_TPI *tpi;
int i, num_tpis;
event = wap_event_create(RcvAck);
event->u.RcvAck.tid = pdu->u.Ack.tid;
event->u.RcvAck.tid_ok = pdu->u.Ack.tidverify;
event->u.RcvAck.rid = pdu->u.Ack.rid;
event->u.RcvAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
/* Set default to 0 because Ack on 1 piece message has no tpi */
event->u.RcvAck.psn = 0;
num_tpis = gwlist_len(pdu->options);
for (i = 0; i < num_tpis; i++) {
tpi = gwlist_get(pdu->options, i);
if (tpi->type == TPI_PSN) {
event->u.RcvAck.psn = octstr_get_bits(tpi->data,0,8);
break;
}
}
return event;
}
static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
{
WAPEvent *event;
event = wap_event_create(RcvNegativeAck);
event->u.RcvNegativeAck.tid = pdu->u.Negative_ack.tid;
event->u.RcvNegativeAck.rid = pdu->u.Negative_ack.rid;
event->u.RcvNegativeAck.nmissing = pdu->u.Negative_ack.nmissing;
event->u.RcvNegativeAck.missing = octstr_duplicate(pdu->u.Negative_ack.missing);
event->u.RcvNegativeAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
return event;
}
static WAPEvent *unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
{
WAPEvent *event;
event = wap_event_create(RcvAbort);
event->u.RcvAbort.tid = pdu->u.Abort.tid;
event->u.RcvAbort.abort_type = pdu->u.Abort.abort_type;
event->u.RcvAbort.abort_reason = pdu->u.Abort.abort_reason;
event->u.RcvAbort.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
return event;
}
static WAPEvent *pack_error(WAPEvent *datagram)
{
WAPEvent *event;
gw_assert(datagram->type == T_DUnitdata_Ind);
event = wap_event_create(RcvErrorPDU);
event->u.RcvErrorPDU.tid = deduce_tid(datagram->u.T_DUnitdata_Ind.user_data);
event->u.RcvErrorPDU.addr_tuple =
wap_addr_tuple_duplicate(datagram->u.T_DUnitdata_Ind.addr_tuple);
return event;
}
/*
* Transfers data from fields of a message to fields of WTP event. User data
* has the host byte order. Updates the log.
*
* This function does incoming events check nro 4 (checking illegal headers
* WTP 10.2).
*
* Return event, when we have a partially correct message or the message
* received has illegal header (WTP 10.2 nro 4); NULL, when the message was
* truncated or unpacking function returned NULL.
*/
WAPEvent *unpack_wdp_datagram_real(WAPEvent *datagram)
{
WTP_PDU *pdu;
WAPEvent *event;
Octstr *data;
gw_assert(datagram->type == T_DUnitdata_Ind);
data = datagram->u.T_DUnitdata_Ind.user_data;
if (truncated_datagram(datagram)) {
warning(0, "WTP: got a truncated datagram, ignoring");
return NULL;
}
pdu = wtp_pdu_unpack(data);
/*
* wtp_pdu_unpack returned NULL, we have send here a rcv error event,
* but now we silently drop the packet. Because we can't figure out
* in the pack_error() call if the TID value and hence the direction
* inditation is really for initiator or responder.
*/
if (pdu == NULL) {
error(0, "WTP: cannot unpack pdu, dropping packet.");
return NULL;
}
event = NULL;
switch (pdu->type) {
case Invoke:
event = unpack_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
/* if an WTP initiator gets invoke, it would be an illegal pdu. */
if (!wtp_event_is_for_responder(event)){
debug("wap.wtp", 0, "WTP: Invoke when initiator. Message was");
wap_event_destroy(event);
event = pack_error(datagram);
}
break;
case Segmented_invoke:
event = unpack_segmented_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
break;
case Result:
event = unpack_result(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
/* if an WTP responder gets result, it would be an illegal pdu. */
if (wtp_event_is_for_responder(event)){
debug("wap.wtp", 0, "WTP: Result when responder. Message was");
wap_event_destroy(event);
event = pack_error(datagram);
}
break;
case Ack:
event = unpack_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
break;
case Negative_ack:
event = unpack_negative_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
break;
case Abort:
event = unpack_abort(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
break;
default:
event = pack_error(datagram);
debug("wap.wtp", 0, "WTP: Unhandled PDU type. Message was");
wap_event_dump(datagram);
return event;
}
wtp_pdu_destroy(pdu);
wap_event_assert(event);
return event;
}
/*
* Used for debugging and when wtp unpack does not return a tid. We include
* first bit; it tells does message received belong to the initiator or to the
* responder.
*/
static int deduce_tid(Octstr *user_data)
{
return octstr_get_bits(user_data, 8, 16);
}
static int concatenated_message(Octstr *user_data)
{
return octstr_get_char(user_data, 0) == 0x00;
}
gateway-1.4.3/wap/wtp.h 0000644 0001750 0001750 00000013173 11132672002 013767 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp.h - WTP implementation general header, common things for the iniator
* and the responder.
*/
#ifndef WTP_H
#define WTP_H
#include
#include
#include
#include
#include "gwlib/gwlib.h"
#include "wap_addr.h"
#include "wap_events.h"
/*
* Use this structure for storing segments to be reassembled
*/
typedef struct WTPSegment WTPSegment;
/*
* For removing the magic
*/
enum {
NUMBER_OF_ABORT_TYPES = 2,
NUMBER_OF_ABORT_REASONS = 10,
NUMBER_OF_TRANSACTION_CLASSES = 3
};
/*
* For now, timers are defined. They will depend on bearer information fetched
* from address (or from a header field of the protocol speaking with the
* bearerbox). For suggested timers, see WTP, Appendix A.
*/
enum {
L_A_WITH_USER_ACK = 4,
L_R_WITH_USER_ACK = 7,
S_R_WITHOUT_USER_ACK = 3,
S_R_WITH_USER_ACK = 4,
G_R_WITHOUT_USER_ACK = 3,
G_R_WITH_USER_ACK = 3,
W_WITH_USER_ACK = 30
};
/*
* Maximum values for counters (for retransmissions and acknowledgement waiting
* periods)
*/
enum {
AEC_MAX = 6,
MAX_RCR = 8
};
/*
* Types of acknowledgement PDU (normal acknowledgement or tid verification)
*/
enum {
ACKNOWLEDGEMENT = 0,
TID_VERIFICATION = 1
};
/*
* Who is aborting (WTP or WTP user)
*/
enum {
PROVIDER = 0x00,
USER = 0x01
};
/*
* WTP abort types (i.e., provider abort codes defined by WAP)
*/
enum {
UNKNOWN = 0x00,
PROTOERR = 0x01,
INVALIDTID = 0x02,
NOTIMPLEMENTEDCL2 = 0x03,
NOTIMPLEMENTEDSAR = 0x04,
NOTIMPLEMENTEDUACK = 0x05,
WTPVERSIONZERO = 0x06,
CAPTEMPEXCEEDED = 0x07,
NORESPONSE = 0x08,
MESSAGETOOLARGE = 0x09,
NOTIMPLEMENTEDESAR = 0x0A
};
/*
* Transaction classes
*/
enum {
TRANSACTION_CLASS_0 = 0,
TRANSACTION_CLASS_1 = 1,
TRANSACTION_CLASS_2 = 2
};
/*
* Types of acknowledgement
*/
enum {
PROVIDER_ACKNOWLEDGEMENT = 0,
USER_ACKNOWLEDGEMENT = 1
};
/*
* Who is indicating, wtp initiator or responder.
*/
enum {
INITIATOR_INDICATION = 0,
RESPONDER_INDICATION = 1
};
enum {
TPI_ERROR = 0,
TPI_INFO = 1,
TPI_OPTION = 2,
TPI_PSN = 3,
TPI_SDU_BOUNDARY = 4,
TPI_FRAME_BOUNDARY = 5
};
/*
* Responder set first tid, initiator not. So all tids send by initiator are
* greater than 2**15.
*/
#define INITIATOR_TID_LIMIT (1 << 15)
/*
* Transaction is identified by the address four-tuple and tid.
*/
struct machine_pattern {
WAPAddrTuple *tuple;
long tid;
long mid;
};
typedef struct machine_pattern machine_pattern;
/*
* Handles possible concatenated messages. Returns a list of wap events,
* consisting of these events.
*/
List *wtp_unpack_wdp_datagram(WAPEvent *datagram);
/*
* Responder set the first bit of the tid field. If we get a packet from the
* responder, we are the initiator.
*
* Returns 1 for responder, 0 for iniator and -1 for error.
*/
int wtp_event_is_for_responder(WAPEvent *event);
#endif
gateway-1.4.3/wap/wsp_server_push_states.def 0000644 0001750 0001750 00000011224 11132672003 020301 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_push_server_states.def - macro calls to generate rows of the state
* table. See the documentation for guidance how to use and update these.
*
* Note that NULL state is called here SERVER_PUSH_NULL_STATE. Condition 1
* means that an action is unconditional.
*
* By Aarno Syvnen for Wapit Ltd
*/
STATE_NAME(SERVER_PUSH_NULL_STATE)
STATE_NAME(SERVER_PUSH_PUSHING)
ROW(SERVER_PUSH_NULL_STATE,
S_ConfirmedPush_Req,
1,
{
WSP_PDU *pdu;
pdu = make_confirmedpush_pdu(current_event);
send_invoke(sm, pdu, current_event, TRANSACTION_CLASS_1);
},
SERVER_PUSH_PUSHING)
ROW(SERVER_PUSH_PUSHING,
Push_Abort,
1,
{
send_abort_to_initiator(current_event->u.Push_Abort.reason,
pm->transaction_id);
indicate_pushabort(pm, current_event->u.Push_Abort.reason);
},
SERVER_PUSH_NULL_STATE)
ROW(SERVER_PUSH_PUSHING,
TR_Invoke_Cnf,
1,
{
confirm_push(pm);
},
SERVER_PUSH_NULL_STATE)
ROW(SERVER_PUSH_PUSHING,
TR_Abort_Ind,
current_event->u.TR_Abort_Ind.abort_code == WSP_ABORT_DISCONNECT,
{
WAPEvent *wsp_event;
wsp_event = wap_event_create(Disconnect_Event);
wsp_event->u.Disconnect_Event.session_handle = pm->server_push_id;
gwlist_append(queue, wsp_event);
},
SERVER_PUSH_NULL_STATE)
ROW(SERVER_PUSH_PUSHING,
TR_Abort_Ind,
current_event->u.TR_Abort_Ind.abort_code == WSP_ABORT_SUSPEND,
{
WAPEvent *wsp_event;
wsp_event = wap_event_create(Suspend_Event);
wsp_event->u.Suspend_Event.session_handle = pm->server_push_id;
gwlist_append(queue, wsp_event);
},
SERVER_PUSH_NULL_STATE)
ROW(SERVER_PUSH_PUSHING,
TR_Abort_Ind,
current_event->u.TR_Abort_Ind.abort_code != WSP_ABORT_DISCONNECT &&
current_event->u.TR_Abort_Ind.abort_code != WSP_ABORT_SUSPEND,
{
indicate_pushabort(pm, current_event->u.Push_Abort.reason);
},
SERVER_PUSH_NULL_STATE)
#undef STATE_NAME
#undef ROW
gateway-1.4.3/wap/wsp_unit.c 0000644 0001750 0001750 00000026102 11132672003 015015 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_unit.c - Implement WSP Connectionless mode
*
* Lars Wirzenius
*/
#include
#include "gwlib/gwlib.h"
#include "wsp.h"
#include "wsp_pdu.h"
#include "wsp_headers.h"
#include "wap_events.h"
#include "wsp_strings.h"
#include "wap.h"
/*
* Give the status the module:
*
* limbo
* not running at all
* running
* operating normally
* terminating
* waiting for operations to terminate, returning to limbo
*/
static enum { limbo, running, terminating } run_status = limbo;
static wap_dispatch_func_t *dispatch_to_wdp;
static wap_dispatch_func_t *dispatch_to_appl;
static List *queue = NULL;
static void main_thread(void *);
static WAPEvent *pack_into_result_datagram(WAPEvent *event);
static WAPEvent *pack_into_push_datagram(WAPEvent *event);
/***********************************************************************
* Public functions
*/
void wsp_unit_init(wap_dispatch_func_t *datagram_dispatch,
wap_dispatch_func_t *application_dispatch) {
queue = gwlist_create();
gwlist_add_producer(queue);
dispatch_to_wdp = datagram_dispatch;
dispatch_to_appl = application_dispatch;
wsp_strings_init();
run_status = running;
gwthread_create(main_thread, NULL);
}
void wsp_unit_shutdown(void) {
gw_assert(run_status == running);
run_status = terminating;
gwlist_remove_producer(queue);
gwthread_join_every(main_thread);
gwlist_destroy(queue, wap_event_destroy_item);
wsp_strings_shutdown();
}
void wsp_unit_dispatch_event(WAPEvent *event) {
wap_event_assert(event);
gwlist_produce(queue, event);
}
static WAPEvent *unpack_datagram(WAPEvent *datagram) {
WAPEvent *event;
Octstr *os;
WSP_PDU *pdu;
long tid_byte;
int method;
Octstr *method_name;
gw_assert(datagram->type == T_DUnitdata_Ind);
os = NULL;
pdu = NULL;
event = NULL;
os = octstr_duplicate(datagram->u.T_DUnitdata_Ind.user_data);
if (os && octstr_len(os) == 0) {
warning(0, "WSP UNIT: Empty datagram.");
goto error;
}
tid_byte = octstr_get_char(os, 0);
octstr_delete(os, 0, 1);
pdu = wsp_pdu_unpack(os);
if (pdu == NULL)
goto error;
if (pdu->type != Get && pdu->type != Post) {
warning(0, "WSP UNIT: Unsupported PDU type %d", pdu->type);
goto error;
}
event = wap_event_create(S_Unit_MethodInvoke_Ind);
event->u.S_Unit_MethodInvoke_Ind.addr_tuple = wap_addr_tuple_duplicate(
datagram->u.T_DUnitdata_Ind.addr_tuple);
event->u.S_Unit_MethodInvoke_Ind.transaction_id = tid_byte;
switch (pdu->type) {
case Get:
debug("wap.wsp", 0, "Connectionless Get request received.");
method = GET_METHODS + pdu->u.Get.subtype;
event->u.S_Unit_MethodInvoke_Ind.request_uri =
octstr_duplicate(pdu->u.Get.uri);
event->u.S_Unit_MethodInvoke_Ind.request_headers =
wsp_headers_unpack(pdu->u.Get.headers, 0);
event->u.S_Unit_MethodInvoke_Ind.request_body = NULL;
break;
case Post:
debug("wap.wsp", 0, "Connectionless Post request received.");
method = POST_METHODS + pdu->u.Post.subtype;
event->u.S_Unit_MethodInvoke_Ind.request_uri =
octstr_duplicate(pdu->u.Post.uri);
event->u.S_Unit_MethodInvoke_Ind.request_headers =
wsp_headers_unpack(pdu->u.Post.headers, 1);
event->u.S_Unit_MethodInvoke_Ind.request_body =
octstr_duplicate(pdu->u.Post.data);
break;
default:
warning(0, "WSP UNIT: Unsupported PDU type %d", pdu->type);
goto error;
}
method_name = wsp_method_to_string(method);
if (method_name == NULL)
method_name = octstr_format("UNKNOWN%02X", method);
event->u.S_Unit_MethodInvoke_Ind.method = method_name;
octstr_destroy(os);
wsp_pdu_destroy(pdu);
return event;
error:
octstr_destroy(os);
wsp_pdu_destroy(pdu);
wap_event_destroy(event);
return NULL;
}
/***********************************************************************
* Local functions
*/
static void main_thread(void *arg)
{
WAPEvent *e;
WAPEvent *newevent;
while (run_status == running && (e = gwlist_consume(queue)) != NULL) {
debug("wap.wsp.unit", 0, "WSP (UNIT): event arrived");
wap_event_assert(e);
switch (e->type) {
case T_DUnitdata_Ind:
newevent = unpack_datagram(e);
if (newevent != NULL)
dispatch_to_appl(newevent);
break;
case S_Unit_MethodResult_Req:
newevent = pack_into_result_datagram(e);
if (newevent != NULL)
dispatch_to_wdp(newevent);
break;
case S_Unit_Push_Req:
newevent = pack_into_push_datagram(e);
if (newevent != NULL)
dispatch_to_wdp(newevent);
debug("wsp.unit", 0, "WSP (UNIT): delivering to wdp");
break;
default:
warning(0, "WSP UNIT: Unknown event type %d", e->type);
break;
}
wap_event_destroy(e);
}
}
/*
* We do not set TUnitData.ind's SMS-specific fields here, because we do not
* support sending results to the phone over SMS. Wsp, chapter 8.4.1 states
* that "that each peer entity is always associated with an encoding version.".
* So we add Encoding-Version when we are sending something to the client.
* (This includes push, which is not directly mentioned in chapter 8.4.2.70).
*/
static WAPEvent *pack_into_result_datagram(WAPEvent *event) {
WAPEvent *datagram;
struct S_Unit_MethodResult_Req *p;
WSP_PDU *pdu;
Octstr *ospdu;
unsigned char tid;
gw_assert(event->type == S_Unit_MethodResult_Req);
p = &event->u.S_Unit_MethodResult_Req;
http_header_add(p->response_headers, "Encoding-Version", "1.3");
pdu = wsp_pdu_create(Reply);
pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(p->status);
pdu->u.Reply.headers = wsp_headers_pack(p->response_headers, 1, WSP_1_3);
pdu->u.Reply.data = octstr_duplicate(p->response_body);
ospdu = wsp_pdu_pack(pdu);
wsp_pdu_destroy(pdu);
if (ospdu == NULL)
return NULL;
tid = p->transaction_id;
octstr_insert_data(ospdu, 0, (char *)&tid, 1);
datagram = wap_event_create(T_DUnitdata_Req);
datagram->u.T_DUnitdata_Req.addr_tuple =
wap_addr_tuple_duplicate(p->addr_tuple);
datagram->u.T_DUnitdata_Req.user_data = ospdu;
return datagram;
}
/*
* According to WSP table 12, p. 63, push id and transaction id are stored
* into same field. T-UnitData.ind is different for IP and SMS bearer.
*/
static WAPEvent *pack_into_push_datagram(WAPEvent *event) {
WAPEvent *datagram;
WSP_PDU *pdu;
Octstr *ospdu;
unsigned char push_id;
gw_assert(event->type == S_Unit_Push_Req);
debug("wap.wsp.unit", 0, "WSP_UNIT: Connectionless push accepted");
http_header_add(event->u.S_Unit_Push_Req.push_headers,
"Encoding-Version", "1.3");
pdu = wsp_pdu_create(Push);
pdu->u.Push.headers = wsp_headers_pack(
event->u.S_Unit_Push_Req.push_headers, 1, WSP_1_3);
pdu->u.Push.data = octstr_duplicate(
event->u.S_Unit_Push_Req.push_body);
ospdu = wsp_pdu_pack(pdu);
wsp_pdu_destroy(pdu);
if (ospdu == NULL)
return NULL;
push_id = event->u.S_Unit_Push_Req.push_id;
octstr_insert_data(ospdu, 0, (char *)&push_id, 1);
datagram = wap_event_create(T_DUnitdata_Req);
datagram->u.T_DUnitdata_Req.addr_tuple =
wap_addr_tuple_duplicate(event->u.S_Unit_Push_Req.addr_tuple);
datagram->u.T_DUnitdata_Req.address_type =
event->u.S_Unit_Push_Req.address_type;
if (event->u.S_Unit_Push_Req.smsc_id != NULL)
datagram->u.T_DUnitdata_Req.smsc_id =
octstr_duplicate(event->u.S_Unit_Push_Req.smsc_id);
else
datagram->u.T_DUnitdata_Req.smsc_id = NULL;
if (event->u.S_Unit_Push_Req.dlr_url != NULL)
datagram->u.T_DUnitdata_Req.dlr_url =
octstr_duplicate(event->u.S_Unit_Push_Req.dlr_url);
else
datagram->u.T_DUnitdata_Req.dlr_url = NULL;
datagram->u.T_DUnitdata_Req.dlr_mask = event->u.S_Unit_Push_Req.dlr_mask;
if (event->u.S_Unit_Push_Req.smsbox_id != NULL)
datagram->u.T_DUnitdata_Req.smsbox_id =
octstr_duplicate(event->u.S_Unit_Push_Req.smsbox_id);
else
datagram->u.T_DUnitdata_Req.smsbox_id = NULL;
datagram->u.T_DUnitdata_Req.service_name =
octstr_duplicate(event->u.S_Unit_Push_Req.service_name);
datagram->u.T_DUnitdata_Req.user_data = ospdu;
return datagram;
}
gateway-1.4.3/wap/wsp_strings.h 0000644 0001750 0001750 00000011023 11132672003 015530 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wsp-strings.h: interface to tables defined by WSP standard
*
* This file defines an interface to the Assigned Numbers tables
* in appendix A of the WSP specification. For each supported
* table there is a function to convert from number to string and
* a function to convert from string to number.
*
* The tables are in wsp-strings.def, in a special format suitable for
* use with the C preprocessor, which we abuse liberally to get the
* interface we want.
*
* For a table named foo, these functions will be declared:
*
* Octstr *wsp_foo_to_string(long number);
* - return NULL if the number has no assigned string.
*
* unsigned char *wsp_foo_to_cstr(long number);
* - return NULL if the number has no assigned string.
*
* long wsp_string_to_foo(Octstr *ostr);
* - case-insensitive lookup.
* - Return -1 if the string has no assigned number.
*
* Richard Braakman
*/
#ifndef WSP_STRINGS_H
#define WSP_STRINGS_H
#include "gwlib/gwlib.h"
#include "wap/wsp.h"
/* Must be called before any of the other functions in this file.
* Can be called more than once, in which case multiple shutdowns
* are also required. */
void wsp_strings_init(void);
/* Call this to clean up memory allocations */
void wsp_strings_shutdown(void);
/* Declare the functions */
#define LINEAR(name, strings) \
Octstr *wsp_##name##_to_string(long number); \
unsigned char *wsp_##name##_to_cstr(long number); \
long wsp_string_to_##name(Octstr *ostr); \
long wsp_string_to_versioned_##name(Octstr *ostr, int version);
#define STRING(string)
#include "wsp_strings.def"
/* Define the enumerated types */
#define LINEAR(name, strings)
#define STRING(string)
#define NAMED(name, strings) enum name##_enum { strings name##_dummy };
#define NSTRING(string, name) name,
#define VNSTRING(version, string, name) name,
#include "wsp_strings.def"
#endif
gateway-1.4.3/wap/wap_events.def 0000644 0001750 0001750 00000045565 11132672003 015652 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wap_events.def - definitions for wapbox events
*
* This file uses a pre-processor trick to define the structure of
* structures. See the documentation.
*
* Fields of type HTTPHEADER, CAPABILITIES, and OPTIONAL_OCTSTR may
* be NULL. All other fields must be filled in, unless they are
* otherwise marked.
*
* Fields described in the appropriate spec are listed first. Fields
* specific to Kannel are introduced with an empty line. In some events,
* we have combined fields to form an "address tuple" (see wap_addr.h).
*
* Aarno Syvnen
* Lars Wirzenius
*/
/* WTLS material - make sure the addr_tuple comes first! */
WAPEVENT(T_Unitdata_Ind, "T-Unitdata.ind",
ADDRTUPLE(addr_tuple)
WTLSPDUS(pdu_list)
)
WAPEVENT(SEC_Create_Ind, "SEC-Create.ind",
ADDRTUPLE(addr_tuple)
)
WAPEVENT(SEC_Create_Request_Req, "SEC-Create.req",
ADDRTUPLE(addr_tuple)
)
WAPEVENT(SEC_Terminate_Req, "SEC-Terminate.req",
ADDRTUPLE(addr_tuple)
INTEGER(alert_level)
INTEGER(alert_desc)
)
WAPEVENT(SEC_Exception_Req, "SEC-Exception.req",
ADDRTUPLE(addr_tuple)
INTEGER(alert_level)
INTEGER(alert_desc)
)
WAPEVENT(SEC_Create_Res, "SEC-Create.res",
ADDRTUPLE(addr_tuple)
INTEGER(client_key_id)
INTEGER(bulk_cipher_algo)
INTEGER(mac_algo)
INTEGER(snmode)
INTEGER(krefresh)
)
WAPEVENT(SEC_Exchange_Req, "SEC-Exchange.req",
ADDRTUPLE(addr_tuple)
)
WAPEVENT(SEC_Commit_Req, "SEC-Commit.req",
ADDRTUPLE(addr_tuple)
)
WAPEVENT(SEC_Unitdata_Req, "SEC-Unidata.req",
ADDRTUPLE(addr_tuple)
OCTSTR(user_data)
)
/*
* Transport layer (WDP)
*/
WAPEVENT(T_DUnitdata_Req, "T-DUnitdata.req",
ADDRTUPLE(addr_tuple)
OCTSTR(user_data)
INTEGER(address_type)
OPTIONAL_OCTSTR(smsc_id)
INTEGER(dlr_mask)
OPTIONAL_OCTSTR(dlr_url)
OPTIONAL_OCTSTR(smsbox_id)
OPTIONAL_OCTSTR(service_name)
)
WAPEVENT(T_DUnitdata_Ind, "T-DUnitdata.ind",
ADDRTUPLE(addr_tuple)
OCTSTR(user_data)
)
/*
* Transaction layer (WTP)
*/
WAPEVENT(TR_Invoke_Req, "TR-Invoke.req",
ADDRTUPLE(addr_tuple)
INTEGER(up_flag)
OCTSTR(user_data)
INTEGER(tcl)
INTEGER(handle)
)
WAPEVENT(TR_Invoke_Ind, "TR-Invoke.ind",
INTEGER(ack_type)
OCTSTR(user_data)
INTEGER(tcl)
ADDRTUPLE(addr_tuple)
INTEGER(handle)
)
WAPEVENT(TR_Invoke_Res, "TR-Invoke.res",
INTEGER(handle)
)
WAPEVENT(TR_Invoke_Cnf, "TR-Invoke.cnf",
INTEGER(handle)
ADDRTUPLE(addr_tuple)
)
WAPEVENT(TR_Result_Req, "TR-Result.req",
OCTSTR(user_data)
INTEGER(handle)
)
WAPEVENT(TR_Result_Cnf, "TR-Result.cnf",
INTEGER(handle)
ADDRTUPLE(addr_tuple)
)
WAPEVENT(TR_Abort_Req, "TR-Abort.req",
INTEGER(abort_type)
INTEGER(abort_reason)
INTEGER(handle)
)
WAPEVENT(TR_Abort_Ind, "TR-Abort.ind",
INTEGER(abort_code)
INTEGER(handle)
ADDRTUPLE(addr_tuple)
INTEGER(ir_flag) /* Are we an initiator or a responder */
)
/*
* Session layer (WSP), server side
* These events use the session id as a handle.
*/
WAPEVENT(S_Connect_Ind, "S-Connect.ind",
ADDRTUPLE(addr_tuple)
HTTPHEADER(client_headers)
CAPABILITIES(requested_capabilities)
INTEGER(session_id)
)
WAPEVENT(S_Connect_Res, "S-Connect.res",
HTTPHEADER(server_headers)
CAPABILITIES(negotiated_capabilities)
INTEGER(session_id)
)
WAPEVENT(S_Suspend_Ind, "S-Suspend.ind",
INTEGER(reason)
INTEGER(session_id)
)
WAPEVENT(S_Resume_Ind, "S-Resume.ind",
ADDRTUPLE(addr_tuple)
HTTPHEADER(client_headers)
INTEGER(session_id)
)
WAPEVENT(S_Resume_Res, "S-Resume.res",
HTTPHEADER(server_headers)
INTEGER(session_id)
)
/*
* Session layer (WSP), client side
*/
WAPEVENT(S_Connect_Req, "S-Connect.req",
ADDRTUPLE(addr_tuple)
HTTPHEADER(client_headers)
CAPABILITIES(requested_capabilities)
INTEGER(session_handle)
)
WAPEVENT(S_Suspend_Req, "S-Suspend.req",
INTEGER(session_handle)
)
WAPEVENT(S_Resume_Req, "S-Resume.req",
ADDRTUPLE(addr_tuple)
HTTPHEADER(client_headers)
INTEGER(session_handle)
)
WAPEVENT(S_Resume_Cnf, "S-Resume.cnf",
HTTPHEADER(server_headers)
INTEGER(session_handle)
)
/*
* Session layer (WSP), events shared between server and client side
* On the server side, the "handle" field is always the session id.
*/
WAPEVENT(S_Disconnect_Req, "S-Disconnect.req",
INTEGER(reason_code)
INTEGER(redirect_security) /* Only meaningful if redirecting */
INTEGER(redirect_addresses) /* FIXME: Wrong type, not used */
OPTIONAL_OCTSTR(error_headers)
OPTIONAL_OCTSTR(error_body)
INTEGER(session_handle)
)
WAPEVENT(S_Disconnect_Ind, "S-Disconnect.ind",
INTEGER(reason_code)
INTEGER(redirect_security) /* Only meaningful if redirecting */
INTEGER(redirect_addresses) /* FIXME: Wrong type, not used */
OPTIONAL_OCTSTR(error_headers)
OPTIONAL_OCTSTR(error_body)
INTEGER(session_handle)
)
/*
* Pseudo-events used by session layer
*/
WAPEVENT(Disconnect_Event, "Disconnect",
INTEGER(session_handle)
)
WAPEVENT(Suspend_Event, "Suspend",
INTEGER(session_handle)
)
WAPEVENT(Release_Event, "Release",
INTEGER(dummy)
)
WAPEVENT(Abort_Event, "Abort",
INTEGER(reason)
)
/*
* Per-method events for session layer, server side
*/
WAPEVENT(S_MethodInvoke_Ind, "S-MethodInvoke.ind",
INTEGER(server_transaction_id)
OCTSTR(method) /* All caps */
OCTSTR(request_uri)
HTTPHEADER(request_headers)
OPTIONAL_OCTSTR(request_body)
HTTPHEADER(session_headers)
ADDRTUPLE(addr_tuple)
INTEGER(client_SDU_size)
INTEGER(session_id)
)
WAPEVENT(S_MethodInvoke_Res, "S-MethodInvoke.res",
INTEGER(server_transaction_id)
INTEGER(session_id)
)
WAPEVENT(S_MethodResult_Req, "S-MethodResult.req",
INTEGER(server_transaction_id)
INTEGER(status)
HTTPHEADER(response_headers)
OPTIONAL_OCTSTR(response_body)
INTEGER(session_id)
)
WAPEVENT(S_MethodResult_Cnf, "S-MethodResult.cnf",
INTEGER(server_transaction_id)
INTEGER(session_id)
)
/*
* Per-method events for session layer, client side
*/
WAPEVENT(S_MethodInvoke_Req, "S-MethodInvoke.req",
INTEGER(client_transaction_id)
OCTSTR(method)
OCTSTR(request_uri)
HTTPHEADER(request_headers)
OPTIONAL_OCTSTR(request_body)
INTEGER(session_handle)
)
WAPEVENT(S_MethodInvoke_Cnf, "S-MethodInvoke.cnf",
INTEGER(client_transaction_id)
INTEGER(session_handle)
)
WAPEVENT(S_MethodResult_Ind, "S-MethodResult.ind",
INTEGER(client_transaction_id)
INTEGER(status)
HTTPHEADER(response_headers)
OPTIONAL_OCTSTR(response_body)
INTEGER(session_handle)
)
WAPEVENT(S_MethodResult_Res, "S-MethodResult.res",
INTEGER(client_transaction_id)
INTEGER(session_handle)
)
/*
* Per-method events used by the session layer
* These events are used by both client and server side.
*/
WAPEVENT(S_MethodAbort_Req, "S-MethodAbort.req",
INTEGER(transaction_id)
INTEGER(session_handle)
)
WAPEVENT(S_MethodAbort_Ind, "S-MethodAbort.ind",
INTEGER(transaction_id)
INTEGER(reason)
INTEGER(session_handle)
)
/*
* Per-push events used by the session layer
*/
WAPEVENT(S_Push_Req, "S-Push.req",
HTTPHEADER(push_headers)
OPTIONAL_OCTSTR(push_body)
INTEGER(session_id)
)
WAPEVENT(S_Push_Ind, "S-Push.ind",
HTTPHEADER(push_headers)
OPTIONAL_OCTSTR(push_body)
INTEGER(session_handle)
HTTPHEADER(session_headers)
)
WAPEVENT(S_ConfirmedPush_Req, "S-ConfirmedPush.req",
INTEGER(server_push_id)
HTTPHEADER(push_headers)
OPTIONAL_OCTSTR(push_body)
INTEGER(session_id)
)
WAPEVENT(S_ConfirmedPush_Ind, "S-ConfirmedPush.ind",
INTEGER(client_push_id)
HTTPHEADER(push_headers)
OPTIONAL_OCTSTR(push_body)
INTEGER(session_handle)
)
WAPEVENT(S_ConfirmedPush_Res, "S-ConfirmedPush.res",
INTEGER(client_push_id)
INTEGER(session_handle)
)
WAPEVENT(S_ConfirmedPush_Cnf, "S-ConfirmedPush.cnf",
INTEGER(server_push_id)
INTEGER(session_id)
)
WAPEVENT(S_PushAbort_Ind, "S-PushAbort.ind",
INTEGER(push_id)
INTEGER(reason)
INTEGER(session_id)
)
/*
* The specification of S-PushAbort seems to assume that only the
* client can issue an S-PushAbort.req, and only the server can get
* an S-PushAbort.ind. This is contradicted by the state tables.
* That's why the definitions here use just "push_id" instead of
* server_push_id and client_push_id.
*/
WAPEVENT(S_PushAbort_Req, "S-PushAbort.req",
INTEGER(push_id)
INTEGER(reason)
INTEGER(session_handle)
)
WAPEVENT(Push_Abort, "Internal abort",
INTEGER(reason)
)
/*
* Events created by unpacking T-DUnitdata.ind events.
* Used by WTP layer.
*/
WAPEVENT(RcvInvoke, "RcvInvoke",
OCTSTR(user_data)
INTEGER(tcl)
INTEGER(tid)
INTEGER(tid_new)
INTEGER(rid)
INTEGER(up_flag)
INTEGER(no_cache_supported)
INTEGER(version)
INTEGER(gtr)
INTEGER(ttr)
ADDRTUPLE(addr_tuple)
)
WAPEVENT(RcvSegInvoke, "RcvSegInvoke",
OCTSTR(user_data)
INTEGER(tid)
INTEGER(rid)
INTEGER(no_cache_supported)
INTEGER(gtr)
INTEGER(ttr)
INTEGER(psn)
ADDRTUPLE(addr_tuple)
)
WAPEVENT(RcvResult, "RcvResult",
OCTSTR(user_data)
INTEGER(tid)
INTEGER(rid)
INTEGER(gtr)
INTEGER(ttr)
ADDRTUPLE(addr_tuple)
)
WAPEVENT(RcvAbort, "RcvAbort",
INTEGER(tid)
INTEGER(abort_type)
INTEGER(abort_reason)
ADDRTUPLE(addr_tuple)
)
WAPEVENT(RcvAck, "RcvAck",
INTEGER(tid)
INTEGER(tid_ok)
INTEGER(rid)
INTEGER(psn)
ADDRTUPLE(addr_tuple)
)
WAPEVENT(RcvNegativeAck, "RcvNack",
INTEGER(tid)
INTEGER(rid)
INTEGER(nmissing)
OPTIONAL_OCTSTR(missing)
ADDRTUPLE(addr_tuple)
)
/*
* Other events used by WTP layer.
*/
WAPEVENT(TimerTO_A, "Timeout-A",
INTEGER(handle)
)
WAPEVENT(TimerTO_R, "Timeout-R",
INTEGER(handle)
)
WAPEVENT(TimerTO_W, "Timeout-W",
INTEGER(handle)
)
WAPEVENT(RcvErrorPDU, "RcvErrorPDU",
INTEGER(tid)
ADDRTUPLE(addr_tuple)
)
/*
* Events used by connectionless session protocol (WSP)
*/
WAPEVENT(S_Unit_MethodInvoke_Req, "S-Unit-MethodInvoke.req",
ADDRTUPLE(addr_tuple)
INTEGER(transaction_id)
OCTSTR(method)
OCTSTR(request_uri)
HTTPHEADER(request_headers)
OPTIONAL_OCTSTR(request_body)
)
WAPEVENT(S_Unit_MethodInvoke_Ind, "S-Unit_MethodInvoke.ind",
ADDRTUPLE(addr_tuple)
INTEGER(transaction_id)
OCTSTR(method) /* All caps */
OCTSTR(request_uri)
HTTPHEADER(request_headers)
OPTIONAL_OCTSTR(request_body)
)
WAPEVENT(S_Unit_MethodResult_Req, "S-Unit-MethodResult.req",
ADDRTUPLE(addr_tuple)
INTEGER(transaction_id)
INTEGER(status)
HTTPHEADER(response_headers)
OPTIONAL_OCTSTR(response_body)
)
WAPEVENT(S_Unit_MethodResult_Ind, "S-Unit-MethodResult.ind",
ADDRTUPLE(addr_tuple)
INTEGER(transaction_id)
INTEGER(status)
HTTPHEADER(response_headers)
OPTIONAL_OCTSTR(response_body)
)
WAPEVENT(S_Unit_Push_Req, "S-Unit-Push.req",
ADDRTUPLE(addr_tuple)
INTEGER(push_id)
HTTPHEADER(push_headers)
OPTIONAL_OCTSTR(push_body)
INTEGER(address_type)
OPTIONAL_OCTSTR(smsc_id)
INTEGER(dlr_mask)
OPTIONAL_OCTSTR(dlr_url)
OPTIONAL_OCTSTR(smsbox_id)
OPTIONAL_OCTSTR(service_name)
)
WAPEVENT(S_Unit_Push_Ind, "S-Unit-Push.ind",
ADDRTUPLE(addr_tuple)
INTEGER(push_id)
HTTPHEADER(push_headers)
OPTIONAL_OCTSTR(push_body)
)
/*
* Events used by push OTA protocol, server side
*/
WAPEVENT(Pom_SessionRequest_Req, "Pom-SessionRequest.req",
ADDRTUPLE(addr_tuple)
HTTPHEADER(push_headers)
INTEGER(push_id)
INTEGER(address_type)
OPTIONAL_OCTSTR(smsc_id)
INTEGER(dlr_mask)
OPTIONAL_OCTSTR(dlr_url)
OPTIONAL_OCTSTR(smsbox_id)
OPTIONAL_OCTSTR(service_name)
)
WAPEVENT(Pom_Connect_Ind, "Pom-Connect.ind",
ADDRTUPLE(addr_tuple)
HTTPHEADER(push_headers)
CAPABILITIES(requested_capabilities)
HTTPHEADER(accept_application)
HTTPHEADER(bearer_indication)
INTEGER(session_id)
INTEGER(push_id)
)
WAPEVENT(Pom_Connect_Res, "Pom-Connect.res",
CAPABILITIES(negotiated_capabilities)
INTEGER(session_id)
)
WAPEVENT(Pom_Disconnect_Ind, "Pom-Disconnect.ind",
INTEGER(reason_code)
INTEGER(redirect_security) /* Only meaningful if redirecting*/
INTEGER(redirect_addresses) /* FIXME: Wrong type, not used */
OPTIONAL_OCTSTR(error_headers)
OPTIONAL_OCTSTR(error_body)
INTEGER(session_handle)
)
WAPEVENT(Pom_Suspend_Ind, "Pom-Suspend.ind",
INTEGER(reason)
INTEGER(session_id)
)
WAPEVENT(Pom_Resume_Ind, "Pom-Resume.ind",
ADDRTUPLE(addr_tuple)
HTTPHEADER(client_headers)
HTTPHEADER(bearer_indication)
INTEGER(session_id)
)
WAPEVENT(Po_Push_Req, "Po-Push.req",
HTTPHEADER(push_headers)
INTEGER(authenticated)
INTEGER(trusted)
INTEGER(last)
OPTIONAL_OCTSTR(push_body)
INTEGER(session_handle)
)
WAPEVENT(Po_ConfirmedPush_Req, "Po-ConfirmedPush.req",
INTEGER(server_push_id)
HTTPHEADER(push_headers)
INTEGER(authenticated)
INTEGER(trusted)
INTEGER(last)
OPTIONAL_OCTSTR(push_body)
INTEGER(session_handle)
)
WAPEVENT(Po_ConfirmedPush_Cnf, "Po-ConfirmedPush.Cnf",
INTEGER(server_push_id)
INTEGER(session_handle)
)
WAPEVENT(Po_Unit_Push_Req, "Po-Unit-Push.req",
ADDRTUPLE(addr_tuple)
INTEGER(push_id)
HTTPHEADER(push_headers)
INTEGER(authenticated)
INTEGER(trusted)
INTEGER(last)
OPTIONAL_OCTSTR(push_body)
INTEGER(address_type)
OPTIONAL_OCTSTR(smsc_id)
INTEGER(dlr_mask)
OPTIONAL_OCTSTR(dlr_url)
OPTIONAL_OCTSTR(smsbox_id)
OPTIONAL_OCTSTR(service_name)
)
WAPEVENT(Po_PushAbort_Req, "Po-PushAbort.req",
INTEGER(push_id)
INTEGER(reason)
INTEGER(session_id)
)
WAPEVENT(Po_PushAbort_Ind, "Po-PushAbort.ind",
INTEGER(push_id)
INTEGER(reason)
INTEGER(session_handle)
)
/*
* Following events are used communicating between PPG main module (implement-
* ing main logic of PPG) and PAP module. These are defined in Push Access
* Protocol, chapter 9.
* Note here is one address, one group of push headers, one push body and one
* group of capabilities. We should use list of address_values for multiple
* addresses (optional) and Lists of push headers, push data and capabilities
* for multipart (non-nested mandatory).
* Note, too, that we do not yet support multiple addresses.
* Optional fields, if PAP control message originally does not contain one,
* should be set NULL, and mandatory fields non-NULL.
*/
WAPEVENT(Push_Message, "push-message",
OCTSTR(pi_push_id)
OPTIONAL_OCTSTR(deliver_before_timestamp) /* using PAP format */
OPTIONAL_OCTSTR(deliver_after_timestamp) /* ditto */
OPTIONAL_OCTSTR(source_reference)
OPTIONAL_OCTSTR(ppg_notify_requested_to)
INTEGER(progress_notes_requested)
OCTSTR(address_value) /* as parsed PAP */
INTEGER(address_type)
INTEGER(priority)
INTEGER(delivery_method)
OPTIONAL_OCTSTR(network)
INTEGER(network_required)
OPTIONAL_OCTSTR(bearer)
INTEGER(bearer_required)
HTTPHEADER(push_headers)
OPTIONAL_OCTSTR(push_data)
CAPABILITIES(pi_capabilities)
OPTIONAL_OCTSTR(smsc_id)
INTEGER(dlr_mask)
OPTIONAL_OCTSTR(dlr_url)
OPTIONAL_OCTSTR(smsbox_id)
OPTIONAL_OCTSTR(service_name)
OPTIONAL_OCTSTR(product_name)
)
/*
* Push response element indicates that there will be no more progress notes,
* see Push Access Protocol, 9.3.2.
*/
WAPEVENT(Push_Response, "push-response",
OCTSTR(pi_push_id)
OPTIONAL_OCTSTR(sender_name)
OPTIONAL_OCTSTR(reply_time)
OPTIONAL_OCTSTR(sender_address)
INTEGER(code)
OPTIONAL_OCTSTR(desc)
OPTIONAL_OCTSTR(product_name)
)
/*
* This is for debugging PIs. One note per stage. See Push Access Protocol,
* 9.3.1.PPG main module sends these separately to PAP.
*/
WAPEVENT(Progress_Note, "progress-note",
INTEGER(stage)
OPTIONAL_OCTSTR(note)
OPTIONAL_OCTSTR(time)
)
/*
* Element bad-message-response is defined in PAP, Implementation Note,
* chapter 5.
*/
WAPEVENT(Bad_Message_Response, "badmessage-response",
INTEGER(code)
OPTIONAL_OCTSTR(desc)
OPTIONAL_OCTSTR(bad_message_fragment)
)
#undef WAPEVENT
#undef OCTSTR
#undef OPTIONAL_OCTSTR
#undef INTEGER
#undef WTLSPDUS
#undef HTTPHEADER
#undef ADDRTUPLE
#undef CAPABILITIES
gateway-1.4.3/wap/wsp.h 0000644 0001750 0001750 00000011350 11132672002 013761 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp.h - WSP implementation header
*/
#ifndef WSP_H
#define WSP_H
/*
* int WSP_accepted_extended_methods[] = { -1 };
* int WSP_accepted_header_code_pages[] = { -1 };
*/
typedef enum {
WSP_1_1 = 1,
WSP_1_2 = 2,
WSP_1_3 = 3,
WSP_1_4 = 4,
WSP_1_5 = 5,
WSP_1_6 = 6,
} wsp_encoding;
/* See Table 35 of the WSP standard */
enum wsp_abort_values {
WSP_ABORT_PROTOERR = 0xe0,
WSP_ABORT_DISCONNECT = 0xe1,
WSP_ABORT_SUSPEND = 0xe2,
WSP_ABORT_RESUME = 0xe3,
WSP_ABORT_CONGESTION = 0xe4,
WSP_ABORT_CONNECTERR = 0xe5,
WSP_ABORT_MRUEXCEEDED = 0xe6,
WSP_ABORT_MOREXCEEDED = 0xe7,
WSP_ABORT_PEERREQ = 0xe8,
WSP_ABORT_NETERR = 0xe9,
WSP_ABORT_USERREQ = 0xea,
WSP_ABORT_USERRFS = 0xeb,
WSP_ABORT_USERPND = 0xec,
WSP_ABORT_USERDCR = 0xed,
WSP_ABORT_USERDCU = 0xee
};
typedef struct WSPMachine WSPMachine;
typedef struct WSPMethodMachine WSPMethodMachine;
typedef struct WSPPushMachine WSPPushMachine;
#include "gwlib/gwlib.h"
#include "wap_addr.h"
#include "wap_events.h"
struct WSPMachine {
#define INTEGER(name) long name;
#define OCTSTR(name) Octstr *name;
#define HTTPHEADERS(name) List *name;
#define ADDRTUPLE(name) WAPAddrTuple *name;
#define COOKIES(name) List *name;
#define REFERER(name) Octstr *name;
#define MACHINESLIST(name) List *name;
#define CAPABILITIES(name) List *name;
#define MACHINE(fields) fields
#include "wsp_server_session_machine.def"
};
struct WSPMethodMachine {
#define INTEGER(name) long name;
#define ADDRTUPLE(name) WAPAddrTuple *name;
#define EVENT(name) WAPEvent *name;
#define MACHINE(fields) fields
#include "wsp_server_method_machine.def"
};
struct WSPPushMachine {
#define INTEGER(name) long name;
#define ADDRTUPLE(name) WAPAddrTuple *name;
#define HTTPHEADER(name) List *name;
#define MACHINE(fields) fields
#include "wsp_server_push_machine.def"
};
/*
* Shared stuff.
*/
long wsp_convert_http_status_to_wsp_status(long http_status);
WSPMachine *find_session_machine_by_id(int);
#endif
gateway-1.4.3/wap/wsp.c 0000644 0001750 0001750 00000010075 11132672002 013757 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp.c - Parts of WSP shared between session oriented and connectionless mode
*/
#include
#include "gwlib/gwlib.h"
#include "wsp.h"
#include "wsp_pdu.h"
#include "wsp_headers.h"
#include "wsp_strings.h"
/***********************************************************************
* Public functions
*/
/* Convert HTTP status codes to WSP status codes according
* to WSP Table 36, Status Code Assignments. */
long wsp_convert_http_status_to_wsp_status(long http_status) {
long hundreds, singles;
/*
* The table is regular, and can be expected to stay regular in
* future versions of WSP. The status value is read as XYY,
* so that X is the first digit and Y is the value of the
* second two digits. This is encoded as a hex value 0xAB,
* where A == X and B == YY.
* This limits YY to the range 0-15, so an exception is made
* to allow larger YY values when X is 4. X value 5 is moved up
* to A value 6 to allow more room for YY when X is 4.
*/
hundreds = http_status / 100;
singles = http_status % 100;
if ((hundreds == 4 && singles > 31) ||
(hundreds != 4 && singles > 15) ||
hundreds < 1 || hundreds > 5)
goto bad_status;
if (hundreds > 4)
hundreds++;
return hundreds * 16 + singles;
bad_status:
error(0, "WSP: Unknown status code used internally. Oops.");
return 0x60; /* Status 500, or "Internal Server Error" */
}
gateway-1.4.3/wap/wap_events.h 0000644 0001750 0001750 00000010054 11132672002 015323 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wap_events.h - definitions for wapbox events
*
* Aarno Syvnen
* Lars Wirzenius
*/
#ifndef WAP_EVENTS_H
#define WAP_EVENTS_H
#include "gwlib/gwlib.h"
#include "wap_addr.h"
typedef struct WAPEvent WAPEvent;
/*
* Names of WAPEvents.
*/
typedef enum {
#define WAPEVENT(name, prettyname, fields) name,
#include "wap_events.def"
WAPEventNameCount
} WAPEventName;
/*
* The actual WAPEvent.
*/
struct WAPEvent {
WAPEventName type;
union {
#define WAPEVENT(name, prettyname, fields) struct name { fields } name;
#define OCTSTR(name) Octstr *name;
#define OPTIONAL_OCTSTR(name) Octstr *name; /* May be NULL */
#define INTEGER(name) long name;
#define HTTPHEADER(name) List *name;
#define WTLSPDUS(name) List *name;
#define ADDRTUPLE(name) WAPAddrTuple *name;
#define CAPABILITIES(name) List *name;
#include "wap_events.def"
} u;
};
WAPEvent *wap_event_create_real(WAPEventName type, const char *file, long line,
const char *func);
#define wap_event_create(type) \
gw_claim_area(wap_event_create_real((type), __FILE__, __LINE__, __func__))
void wap_event_destroy(WAPEvent *event);
void wap_event_destroy_item(void *event);
WAPEvent *wap_event_duplicate(WAPEvent *event);
const char *wap_event_name(WAPEventName type);
void wap_event_dump(WAPEvent *event);
void wap_event_assert(WAPEvent *event);
#endif
gateway-1.4.3/wap/wsp_server_push_machine.def 0000644 0001750 0001750 00000006722 11132672002 020410 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_server_push_machine.def: Macro calls to generate monotonous push
* machine code. See documentation for guidance how to update these.
*
* By Aarno Syvnen for Wapit Ltd
*/
#if !defined(MACHINE)
#error "Definition of macro MACHINE is missing"
#elif !defined(INTEGER)
#error "Definition of macro INTEGER is missing"
#elif !defined(ADDRTUPLE)
#error "Definition of macro ADDRTUPLE is missing"
#elif !defined(HTTPHEADER)
#error "Definition of macro HTTPHEADER is missing"
#endif
MACHINE(
INTEGER(state)
INTEGER(server_push_id)
INTEGER(session_id)
INTEGER(transaction_id)
ADDRTUPLE(addr_tuple)
HTTPHEADER(push_header)
)
#undef MACHINE
#undef INTEGER
#undef ADDRTUPLE
#undef HTTPHEADER
#undef OCTSTR
gateway-1.4.3/wap/wsp_headers.c 0000644 0001750 0001750 00000263327 11132672002 015464 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_headers.c - Implement WSP PDU headers
*
* References:
* WSP specification version 1.1
* RFC 2068, Hypertext Transfer Protocol HTTP/1.1
* RFC 2616, Hypertext Transfer Protocol HTTP/1.1
*
* For push headers, WSP specification, June 2000 conformance release
*
* This file has two parts. The first part decodes the request's headers
* from WSP to HTTP. The second part encodes the response's headers from
* HTTP to WSP.
*
* Note that push header encoding and decoding are divided two parts:
* first decoding and encoding numeric values and then packing these values
* into WSP format and unpacking them from WSP format. This module contains
* only packing and unpacking parts.
*
* Some functions are declared non-static to provide them for external use,
* ie. the MMS encapsulation encoding and decoding routines implemented in
* other files.
*
* Richard Braakman
* Stipe Tolj
*/
#include
#include
#include
#include "gwlib/gwlib.h"
#include "wsp.h"
#include "wsp_headers.h"
#include "wsp_strings.h"
/*
* get field value and return its type as predefined data types
* There are three kinds of field encodings:
* WSP_FIELD_VALUE_NUL_STRING: 0-terminated string
* WSP_FIELD_VALUE_ENCODED: short integer, range 0-127
* WSP_FIELD_VALUE_DATA: octet string defined by length
* The function will return one of those values, and modify the parse context
* to make it easy to get the field data.
* WSP_FIELD_VALUE_NUL_STRING: Leave parsing position at start of string
* WSP_FIELD_VALUE_ENCODED: Put value in *well_known_value, leave
* parsing position after field value.
* WSP_FIELD_VALUE_DATA: Leave parsing position at start of data, and set
* a parse limit at the end of data.
*/
int wsp_field_value(ParseContext *context, int *well_known_value)
{
int val;
unsigned long len;
val = parse_get_char(context);
if (val > 0 && val < 31) {
*well_known_value = -1;
parse_limit(context, val);
return WSP_FIELD_VALUE_DATA;
} else if (val == 31) {
*well_known_value = -1;
len = parse_get_uintvar(context);
parse_limit(context, len);
return WSP_FIELD_VALUE_DATA;
} else if (val > 127) {
*well_known_value = val - 128;
return WSP_FIELD_VALUE_ENCODED;
} else if (val == WSP_QUOTE || val == '"') { /* 127 */
*well_known_value = -1;
/* We already consumed the Quote */
return WSP_FIELD_VALUE_NUL_STRING;
} else { /* implicite val == 0 */
*well_known_value = -1;
/* Un-parse the character we just read */
parse_skip(context, -1);
return WSP_FIELD_VALUE_NUL_STRING;
}
}
/* Skip over a field_value as defined above. */
void wsp_skip_field_value(ParseContext *context)
{
int val;
int ret;
ret = wsp_field_value(context, &val);
if (ret == WSP_FIELD_VALUE_DATA) {
parse_skip_to_limit(context);
parse_pop_limit(context);
}
}
/* Multi-octet-integer is defined in 8.4.2.1 */
static long unpack_multi_octet_integer(ParseContext *context, long len)
{
long val = 0;
if (len > (long) sizeof(val) || len < 0)
return -1;
while (len > 0) {
val = val * 256 + parse_get_char(context);
len--;
}
if (parse_error(context))
return -1;
return val;
}
/* This function is similar to field_value, but it is used at various
* places in the grammar where we expect either an Integer-value
* or some kind of NUL-terminated text.
*
* Return values are just like field_value except that WSP_FIELD_VALUE_DATA
* will not be returned.
*
* As a special case, we parse a 0-length Long-integer as an
* WSP_FIELD_VALUE_NONE, so that we can distinguish between No-value
* and an Integer-value of 0. (A real integer 0 would be encoded as
* a Short-integer; the definition of Long-integer seems to allow
* 0-length integers, but the definition of Multi-octet-integer does
* not, so this is an unclear area of the specification.)
*/
int wsp_secondary_field_value(ParseContext *context, long *result)
{
int val;
long length;
val = parse_get_char(context);
if (val == 0) {
*result = 0;
return WSP_FIELD_VALUE_NONE;
} else if (val > 0 && val < 31) {
*result = unpack_multi_octet_integer(context, val);
return WSP_FIELD_VALUE_ENCODED;
} else if (val == 31) {
length = parse_get_uintvar(context);
*result = unpack_multi_octet_integer(context, length);
return WSP_FIELD_VALUE_ENCODED;
} else if (val > 127) {
*result = val - 128;
return WSP_FIELD_VALUE_ENCODED;
} else if (val == WSP_QUOTE) { /* 127 */
*result = -1;
return WSP_FIELD_VALUE_NUL_STRING;
} else {
*result = -1;
/* Un-parse the character we just read */
parse_skip(context, -1);
return WSP_FIELD_VALUE_NUL_STRING;
}
}
/* Integer-value is defined in 8.4.2.3 */
Octstr *wsp_unpack_integer_value(ParseContext *context)
{
Octstr *decoded;
unsigned long value;
int val;
val = parse_get_char(context);
if (val < 31) {
value = unpack_multi_octet_integer(context, val);
} else if (val > 127) {
value = val - 128;
} else {
warning(0, "WSP headers: bad integer-value.");
return NULL;
}
decoded = octstr_create("");
octstr_append_decimal(decoded, value);
return decoded;
}
/* Q-value is defined in 8.4.2.3 */
static Octstr *convert_q_value(int q)
{
Octstr *result = NULL;
/* When quality factor 0 and quality factors with one or two
* decimal digits are encoded, they shall be multiplied by 100
* and incremented by one, so that they encode as a one-octet
* value in range 1-100. */
if (q >= 1 && q <= 100) {
q = q - 1;
result = octstr_create("0.");
octstr_append_char(result, (q / 10) + '0');
if (q % 10 > 0)
octstr_append_char(result, (q % 10) + '0');
return result;
}
/* Three decimal quality factors shall be multiplied with 1000
* and incremented by 100. */
if (q > 100 && q <= 1000) {
q = q - 100;
result = octstr_create("0.");
octstr_append_char(result, (q / 100) + '0');
if (q % 100 > 0)
octstr_append_char(result, (q / 10 % 10) + '0');
if (q % 10 > 0)
octstr_append_char(result, (q % 10) + '0');
return result;
}
return NULL;
}
/* Q-value is defined in 8.4.2.3 */
static Octstr *unpack_q_value(ParseContext *context)
{
int c, c2;
c = parse_get_char(context);
if (c < 0)
return NULL;
if (c & 0x80) {
c2 = parse_get_char(context);
if (c2 < 0 || (c2 & 0x80))
return NULL;
c = ((c & 0x7f) << 8) + c2;
}
return convert_q_value(c);
}
/* Version-value is defined in 8.4.2.3. Encoding-Version uses coding
* defined in this chapter, see 8.4.2.70. */
Octstr *wsp_unpack_version_value(long value)
{
Octstr *result;
int major, minor;
major = ((value >> 4) & 0x7);
minor = (value & 0xf);
result = octstr_create("");
octstr_append_char(result, major + '0');
if (minor != 15) {
octstr_append_char(result, '.');
octstr_append_decimal(result, minor);
}
return result;
}
static Octstr *unpack_encoding_version(ParseContext *context)
{
int ch;
ch = parse_get_char(context);
if (ch < 128) {
warning(0, "WSP: bad Encoding-Version value");
return NULL;
}
return wsp_unpack_version_value(((long) ch) - 128);
}
/* Called with the parse limit set to the end of the parameter data,
* and decoded containing the unpacked header line so far.
* Parameter is defined in 8.4.2.4. */
static int unpack_parameter(ParseContext *context, Octstr *decoded)
{
Octstr *parm = NULL;
Octstr *value = NULL;
int ret;
long type;
long val;
ret = wsp_secondary_field_value(context, &type);
if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
warning(0, "bad parameter");
goto error;
}
if (ret == WSP_FIELD_VALUE_ENCODED) {
/* Typed-parameter */
parm = wsp_parameter_to_string(type);
if (!parm)
warning(0, "Unknown parameter %02lx.", type);
} else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
/* Untyped-parameter */
parm = parse_get_nul_string(context);
if (!parm)
warning(0, "Format error in parameter.");
type = -1;
/* We treat Untyped-value as a special type. Its format
* Integer-value | Text-value is pretty similar to most
* typed formats. */
} else {
panic(0, "Unknown secondary field value type %d.", ret);
}
if (type == 0x00) /* q */
value = unpack_q_value(context);
else {
ret = wsp_secondary_field_value(context, &val);
if (parse_error(context)) {
warning(0, "bad parameter value");
goto error;
}
if (ret == WSP_FIELD_VALUE_ENCODED) {
switch (type) {
case -1: /* untyped: Integer-value */
case 3: /* type: Integer-value */
case 8: /* padding: Short-integer */
value = octstr_create("");
octstr_append_decimal(value, val);
break;
case 0: /* q, already handled above */
gw_assert(0);
break;
case 1: /* charset: Well-known-charset */
value = wsp_charset_to_string(val);
if (!value)
warning(0, "Unknown charset %04lx.", val);
break;
case 2: /* level: Version-value */
value = wsp_unpack_version_value(val);
break;
case 5: /* name: Text-string */
case 6: /* filename: Text-string */
warning(0, "Text-string parameter with integer encoding");
break;
case 7: /* differences: Field-name */
value = wsp_header_to_string(val);
if (!value)
warning(0, "Unknown differences header %02lx.", val);
break;
default:
warning(0, "Unknown parameter encoding %02lx.",
type);
break;
}
} else if (ret == WSP_FIELD_VALUE_NONE) {
value = octstr_create("");
} else {
gw_assert(ret == WSP_FIELD_VALUE_NUL_STRING);
/* Text-value = No-value | Token-text | Quoted-string */
value = parse_get_nul_string(context);
if (!value)
warning(0, "Format error in parameter value.");
else {
if (octstr_get_char(value, 0) == '"') {
/* Quoted-string */
octstr_append_char(value, '"');
} else { /* DAVI! */
octstr_insert(value, octstr_imm("\""), 0);
octstr_append_char(value, '"');
}
}
}
}
if (!parm || !value) {
warning(0, "Skipping parameters");
goto error;
}
octstr_append(decoded, octstr_imm("; "));
octstr_append(decoded, parm);
if (octstr_len(value) > 0) {
octstr_append_char(decoded, '=');
octstr_append(decoded, value);
}
octstr_destroy(parm);
octstr_destroy(value);
return 0;
error:
parse_skip_to_limit(context);
octstr_destroy(parm);
octstr_destroy(value);
parse_set_error(context);
return -1;
}
void wsp_unpack_all_parameters(ParseContext *context, Octstr *decoded)
{
int ret = 0;
while (ret >= 0 && !parse_error(context) &&
parse_octets_left(context) > 0) {
ret = unpack_parameter(context, decoded);
}
}
/* Unpack parameters in the format used by credentials and challenge,
* which differs from the format used by all other HTTP headers. */
static void unpack_broken_parameters(ParseContext *context, Octstr *decoded)
{
int ret = 0;
int first = 1;
long pos;
while (ret >= 0 && !parse_error(context) &&
parse_octets_left(context) > 0) {
pos = octstr_len(decoded);
ret = unpack_parameter(context, decoded);
if (ret >= 0) {
if (first) {
/* Zap ';' */
octstr_delete(decoded, pos, 1);
first = 0;
} else {
/* Replace ';' with ',' */
octstr_set_char(decoded, pos, first ? ' ' : ',');
}
}
}
}
static void unpack_optional_q_value(ParseContext *context, Octstr *decoded)
{
if (parse_octets_left(context) > 0) {
Octstr *qval = unpack_q_value(context);
if (qval) {
octstr_append(decoded, octstr_imm("; q="));
octstr_append(decoded, qval);
octstr_destroy(qval);
} else
warning(0, "Bad q-value");
}
}
/* Date-value is defined in 8.4.2.3. */
Octstr *wsp_unpack_date_value(ParseContext *context)
{
unsigned long timeval;
int length;
length = parse_get_char(context);
if (length > 30) {
warning(0, "WSP headers: bad date-value.");
return NULL;
}
timeval = unpack_multi_octet_integer(context, length);
if (timeval < 0) {
warning(0, "WSP headers: cannot unpack date-value.");
return NULL;
}
return date_format_http(timeval);
}
/* Accept-general-form is defined in 8.4.2.7 */
Octstr *wsp_unpack_accept_general_form(ParseContext *context)
{
Octstr *decoded = NULL;
int ret;
long val;
/* The definition for Accept-general-form looks quite complicated,
* but the "Q-token Q-value" part fits the normal expansion of
* Parameter, so it simplifies to:
* Value-length Media-range *(Parameter)
* and we've already parsed Value-length.
*/
/* We use this function to parse content-general-form too,
* because its definition of Media-type is identical to Media-range.
*/
ret = wsp_secondary_field_value(context, &val);
if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
warning(0, "bad media-range or media-type");
return NULL;
}
if (ret == WSP_FIELD_VALUE_ENCODED) {
decoded = wsp_content_type_to_string(val);
if (!decoded) {
warning(0, "Unknown content type 0x%02lx.", val);
return NULL;
}
} else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
decoded = parse_get_nul_string(context);
if (!decoded) {
warning(0, "Format error in content type");
return NULL;
}
} else {
panic(0, "Unknown secondary field value type %d.", ret);
}
wsp_unpack_all_parameters(context, decoded);
return decoded;
}
/* Accept-charset-general-form is defined in 8.4.2.8 */
Octstr *wsp_unpack_accept_charset_general_form(ParseContext *context)
{
Octstr *decoded = NULL;
int ret;
long val;
ret = wsp_secondary_field_value(context, &val);
if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
warning(0, "Bad accept-charset-general-form");
return NULL;
}
if (ret == WSP_FIELD_VALUE_ENCODED) {
decoded = wsp_charset_to_string(val);
if (!decoded) {
warning(0, "Unknown character set %04lx.", val);
return NULL;
}
} else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
decoded = parse_get_nul_string(context);
if (!decoded) {
warning(0, "Format error in accept-charset");
return NULL;
}
} else {
panic(0, "Unknown secondary field value type %d.", ret);
}
unpack_optional_q_value(context, decoded);
return decoded;
}
/* Accept-language-general-form is defined in 8.4.2.10 */
static Octstr *unpack_accept_language_general_form(ParseContext *context)
{
Octstr *decoded = NULL;
int ret;
long val;
ret = wsp_secondary_field_value(context, &val);
if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
warning(0, "Bad accept-language-general-form");
return NULL;
}
if (ret == WSP_FIELD_VALUE_ENCODED) {
/* Any-language is handled by a special entry in the
* language table. */
decoded = wsp_language_to_string(val);
if (!decoded) {
warning(0, "Unknown language %02lx.", val);
return NULL;
}
} else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
decoded = parse_get_nul_string(context);
if (!decoded) {
warning(0, "Format error in accept-language");
return NULL;
}
} else {
panic(0, "Unknown secondary field value type %d.", ret);
}
unpack_optional_q_value(context, decoded);
return decoded;
}
/* Credentials is defined in 8.4.2.5 */
static Octstr *unpack_credentials(ParseContext *context)
{
Octstr *decoded = NULL;
int val;
val = parse_peek_char(context);
if (val == BASIC_AUTHENTICATION) {
Octstr *userid, *password;
parse_skip(context, 1);
userid = parse_get_nul_string(context);
password = parse_get_nul_string(context);
if (parse_error(context)) {
octstr_destroy(userid);
octstr_destroy(password);
} else {
/* Create the user-pass cookie */
decoded = octstr_duplicate(userid);
octstr_append_char(decoded, ':');
octstr_append(decoded, password);
/* XXX Deal with cookies that overflow the 76-per-line
* limit of base64. Either go through and zap all
* CR LF sequences, or give the conversion function
* a flag or something to leave them out. */
octstr_binary_to_base64(decoded);
/* Zap the CR LF at the end */
octstr_delete(decoded, octstr_len(decoded) - 2, 2);
octstr_insert_data(decoded, 0, "Basic ", 6);
octstr_destroy(userid);
octstr_destroy(password);
}
} else if (val >= 32 && val < 128) {
/* Generic authentication scheme */
decoded = parse_get_nul_string(context);
if (decoded)
unpack_broken_parameters(context, decoded);
}
if (!decoded)
warning(0, "Cannot parse credentials.");
return decoded;
}
/* Credentials is defined in 8.4.2.5
* but as Proxy-Authentication is to be used by kannel,
* a simplier to parse version is used here */
static Octstr *proxy_unpack_credentials(ParseContext *context)
{
Octstr *decoded = NULL;
int val;
val = parse_peek_char(context);
if (val == BASIC_AUTHENTICATION) {
Octstr *userid, *password;
parse_skip(context, 1);
userid = parse_get_nul_string(context);
password = parse_get_nul_string(context);
if (parse_error(context)) {
octstr_destroy(userid);
octstr_destroy(password);
} else {
/* Create the user-pass cookie */
decoded = octstr_duplicate(userid);
octstr_append_char(decoded, ':');
octstr_append(decoded, password);
octstr_destroy(userid);
octstr_destroy(password);
}
} else if (val >= 32 && val < 128) {
/* Generic authentication scheme */
decoded = parse_get_nul_string(context);
if (decoded)
unpack_broken_parameters(context, decoded);
}
if (!decoded)
warning(0, "Cannot parse credentials.");
return decoded;
}
/* Challenge is defined in 8.4.2.5 */
static Octstr *unpack_challenge(ParseContext *context)
{
Octstr *decoded = NULL;
Octstr *realm_value = NULL;
int val;
val = parse_peek_char(context);
if (val == BASIC_AUTHENTICATION) {
parse_skip(context, 1);
realm_value = parse_get_nul_string(context);
if (realm_value) {
decoded = octstr_create("Basic realm=\"");
octstr_append(decoded, realm_value);
octstr_append_char(decoded, '"');
}
} else if (val >= 32 && val < 128) {
/* Generic authentication scheme */
decoded = parse_get_nul_string(context);
realm_value = parse_get_nul_string(context);
if (decoded && realm_value) {
octstr_append(decoded,
octstr_imm(" realm=\""));
octstr_append(decoded, realm_value);
octstr_append_char(decoded, '"');
if (parse_octets_left(context) > 0) {
/* Prepare for following parameter list */
octstr_append_char(decoded, ',');
}
unpack_broken_parameters(context, decoded);
}
}
if (!decoded)
warning(0, "Cannot parse challenge.");
octstr_destroy(realm_value);
return decoded;
}
/* Content-range is defined in 8.4.2.23 */
static Octstr *unpack_content_range(ParseContext *context)
{
/* We'd have to figure out how to access the content range
* length (i.e. user_data size) from here to parse this,
* and I don't see why the _client_ would send this in any case. */
warning(0, "Decoding of content-range not supported");
return NULL;
/*
Octstr *decoded = NULL;
unsigned long first_byte_pos, entity_length;
unsigned long last_byte_pos;
first_byte_pos = parse_get_uintvar(context);
entity_length = parse_get_uintvar(context);
if (parse_error(context)) {
warning(0, "Cannot parse content-range header");
return NULL;
}
decoded = octstr_create("bytes ");
octstr_append_decimal(decoded, first_byte_pos);
octstr_append_char(decoded, '-');
octstr_append_decimal(decoded, last_byte_pos);
octstr_append_char(decoded, '/');
octstr_append_decimal(decoded, entity_length);
return decoded;
*/
}
/* Field-name is defined in 8.4.2.6 */
static Octstr *unpack_field_name(ParseContext *context)
{
Octstr *decoded = NULL;
int ret;
int val;
ret = wsp_field_value(context, &val);
if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) {
warning(0, "Bad field-name encoding");
return NULL;
}
if (ret == WSP_FIELD_VALUE_ENCODED) {
decoded = wsp_header_to_string(val);
if (!decoded) {
warning(0, "Unknown field-name 0x%02x.", val);
return NULL;
}
} else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
decoded = parse_get_nul_string(context);
if (!decoded) {
warning(0, "Bad field-name encoding");
return NULL;
}
} else {
panic(0, "Unknown field value type %d.", ret);
}
return decoded;
}
/* Cache-directive is defined in 8.4.2.15 */
static Octstr *unpack_cache_directive(ParseContext *context)
{
Octstr *decoded = NULL;
int ret;
int val;
ret = wsp_field_value(context, &val);
if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) {
warning(0, "Bad cache-directive");
goto error;
}
if (ret == WSP_FIELD_VALUE_ENCODED) {
decoded = wsp_cache_control_to_string(val);
if (!decoded) {
warning(0, "Bad cache-directive 0x%02x.", val);
goto error;
}
octstr_append_char(decoded, '=');
switch (val) {
case WSP_CACHE_CONTROL_NO_CACHE:
case WSP_CACHE_CONTROL_PRIVATE:
if (parse_octets_left(context) == 0) {
warning(0, "Too short cache-directive");
goto error;
}
octstr_append_char(decoded, '"');
do {
Octstr *fieldname = unpack_field_name(context);
if (!fieldname) {
warning(0, "Bad field name in cache directive");
goto error;
}
octstr_append(decoded, fieldname);
octstr_destroy(fieldname);
if (parse_octets_left(context) > 0) {
octstr_append_char(decoded, ',');
octstr_append_char(decoded, ' ');
}
} while (parse_octets_left(context) > 0 &&
!parse_error(context));
octstr_append_char(decoded, '"');
break;
case WSP_CACHE_CONTROL_MAX_AGE:
case WSP_CACHE_CONTROL_MAX_STALE:
case WSP_CACHE_CONTROL_MIN_FRESH:
{
Octstr *seconds;
seconds = wsp_unpack_integer_value(context);
if (!seconds) {
warning(0, "Bad integer value in cache directive");
goto error;
}
octstr_append(decoded, seconds);
octstr_destroy(seconds);
}
break;
default:
warning(0, "Unexpected value 0x%02x in cache directive.", val);
break;
}
} else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
/* XXX: WSP grammar seems wrong here. It works out
* to Token-text followed by Parameter. But the
* grammar in RFC2616 works out to a key = value
* pair, i.e. only a Parameter. */
decoded = parse_get_nul_string(context);
if (!decoded) {
warning(0, "Format error in cache-control.");
return NULL;
}
/* Yes, the grammar allows only one */
unpack_parameter(context, decoded);
} else {
panic(0, "Unknown field value type %d.", ret);
}
return decoded;
error:
octstr_destroy(decoded);
return NULL;
}
/* Retry-after is defined in 8.4.2.44 */
static Octstr *unpack_retry_after(ParseContext *context)
{
int selector;
selector = parse_get_char(context);
if (selector == ABSOLUTE_TIME) {
return wsp_unpack_date_value(context);
} else if (selector == RELATIVE_TIME) {
return wsp_unpack_integer_value(context);
} else {
warning(0, "Cannot parse retry-after value.");
return NULL;
}
}
/* Disposition is defined in 8.4.2.53 */
static Octstr *unpack_disposition(ParseContext *context)
{
Octstr *decoded = NULL;
int selector;
selector = parse_get_char(context) - 128;
decoded = wsp_disposition_to_string(selector);
if (!decoded) {
warning(0, "Cannot parse content-disposition value.");
return NULL;
}
wsp_unpack_all_parameters(context, decoded);
return decoded;
}
/* Range-value is defined in 8.4.2.42 */
static Octstr *unpack_range_value(ParseContext *context)
{
Octstr *decoded = NULL;
int selector;
unsigned long first_byte_pos, last_byte_pos, suffix_length;
selector = parse_get_char(context);
if (selector == BYTE_RANGE) {
first_byte_pos = parse_get_uintvar(context);
if (parse_error(context))
goto error;
decoded = octstr_create("bytes = ");
octstr_append_decimal(decoded, first_byte_pos);
octstr_append_char(decoded, '-');
last_byte_pos = parse_get_uintvar(context);
if (parse_error(context)) {
/* last_byte_pos is optional */
parse_clear_error(context);
} else {
octstr_append_decimal(decoded, last_byte_pos);
}
} else if (selector == SUFFIX_BYTE_RANGE) {
suffix_length = parse_get_uintvar(context);
if (parse_error(context))
goto error;
decoded = octstr_create("bytes = -");
octstr_append_decimal(decoded, suffix_length);
} else {
goto error;
}
return decoded;
error:
warning(0, "Bad format for range-value.");
octstr_destroy(decoded);
return NULL;
}
/* Warning-value is defined in 8.4.2.51 */
static Octstr *unpack_warning_value(ParseContext *context)
{
Octstr *decoded = NULL;
Octstr *warn_code = NULL;
Octstr *warn_agent = NULL;
Octstr *warn_text = NULL;
unsigned char quote = '"';
warn_code = wsp_unpack_integer_value(context);
warn_agent = parse_get_nul_string(context);
if (warn_agent && octstr_get_char(warn_agent, 0) == WSP_QUOTE)
octstr_delete(warn_agent, 0, 1);
warn_text = parse_get_nul_string(context);
if (warn_text && octstr_get_char(warn_text, 0) == WSP_QUOTE)
octstr_delete(warn_text, 0, 1);
if (octstr_get_char(warn_text, 0) != quote)
octstr_insert_data(warn_text, 0, (char *)"e, 1);
if (octstr_get_char(warn_text, octstr_len(warn_text) - 1) != quote)
octstr_append_char(warn_text, quote);
if (parse_error(context) || !warn_agent || !warn_text)
goto error;
decoded = octstr_create("");
octstr_append(decoded, warn_code);
octstr_append_char(decoded, ' ');
octstr_append(decoded, warn_agent);
octstr_append_char(decoded, ' ');
octstr_append(decoded, warn_text);
octstr_destroy(warn_agent);
octstr_destroy(warn_code);
octstr_destroy(warn_text);
return decoded;
error:
warning(0, "Bad format for warning-value.");
octstr_destroy(warn_agent);
octstr_destroy(warn_code);
octstr_destroy(warn_text);
octstr_destroy(decoded);
return NULL;
}
void wsp_unpack_well_known_field(List *unpacked, int field_type,
ParseContext *context)
{
int val, ret;
unsigned char *headername = NULL;
unsigned char *ch = NULL;
Octstr *decoded = NULL;
ret = wsp_field_value(context, &val);
if (parse_error(context)) {
warning(0, "Faulty header, skipping remaining headers.");
parse_skip_to_limit(context);
return;
}
headername = wsp_header_to_cstr(field_type);
/* headername can still be NULL. This is checked after parsing
* the field value. We want to parse the value before exiting,
* so that we are ready for the next header. */
/* The following code must set "ch" or "decoded" to a non-NULL
* value if the header is valid. */
if (ret == WSP_FIELD_VALUE_NUL_STRING) {
/* We allow any header to have a text value, even if that
* is not defined in the grammar. Be generous in what
* you accept, etc. */
/* This covers Text-string, Token-Text, and Uri-value rules */
decoded = parse_get_nul_string(context);
} else if (ret == WSP_FIELD_VALUE_ENCODED) {
switch (field_type) {
case WSP_HEADER_ACCEPT:
case WSP_HEADER_CONTENT_TYPE:
ch = wsp_content_type_to_cstr(val);
if (!ch)
warning(0, "Unknown content type 0x%02x.", val);
break;
case WSP_HEADER_ACCEPT_CHARSET:
ch = wsp_charset_to_cstr(val);
if (!ch)
warning(0, "Unknown charset 0x%02x.", val);
break;
case WSP_HEADER_ACCEPT_ENCODING:
case WSP_HEADER_CONTENT_ENCODING:
ch = wsp_encoding_to_cstr(val);
if (!ch)
warning(0, "Unknown encoding 0x%02x.", val);
break;
case WSP_HEADER_ACCEPT_LANGUAGE:
case WSP_HEADER_CONTENT_LANGUAGE:
ch = wsp_language_to_cstr(val);
if (!ch)
warning(0, "Unknown language 0x%02x.", val);
break;
case WSP_HEADER_ACCEPT_RANGES:
ch = wsp_ranges_to_cstr(val);
if (!ch)
warning(0, "Unknown ranges value 0x%02x.", val);
break;
case WSP_HEADER_AGE:
case WSP_HEADER_CONTENT_LENGTH:
case WSP_HEADER_MAX_FORWARDS:
/* Short-integer version of Integer-value */
decoded = octstr_create("");
octstr_append_decimal(decoded, val);
break;
case WSP_HEADER_ALLOW:
case WSP_HEADER_PUBLIC:
ch = wsp_method_to_cstr(val);
if (!ch) {
/* FIXME Support extended methods */
warning(0, "Unknown method 0x%02x.", val);
}
break;
case WSP_HEADER_CACHE_CONTROL:
case WSP_HEADER_CACHE_CONTROL_V13:
case WSP_HEADER_CACHE_CONTROL_V14:
ch = wsp_cache_control_to_cstr(val);
if (!ch)
warning(0, "Unknown cache-control value 0x%02x.", val);
break;
case WSP_HEADER_CONNECTION:
ch = wsp_connection_to_cstr(val);
if (!ch)
warning(0, "Unknown connection value 0x%02x.", val);
break;
case WSP_HEADER_PRAGMA:
if (val == 0)
ch = (unsigned char *)"no-cache";
else
warning(0, "Unknown pragma value 0x%02x.", val);
break;
case WSP_HEADER_TRANSFER_ENCODING:
ch = wsp_transfer_encoding_to_cstr(val);
if (!ch)
warning(0, "Unknown transfer encoding value 0x%02x.", val);
break;
case WSP_HEADER_VARY:
ch = wsp_header_to_cstr(val);
if (!ch)
warning(0, "Unknown Vary field name 0x%02x.", val);
break;
case WSP_HEADER_WARNING:
decoded = octstr_create("");
octstr_append_decimal(decoded, val);
break;
case WSP_HEADER_BEARER_INDICATION:
ch = wsp_bearer_indication_to_cstr(val);
if (!ch)
warning(0, "Unknown Bearer-Indication field name 0x%02x.", val);
break;
case WSP_HEADER_ACCEPT_APPLICATION:
ch = wsp_application_id_to_cstr(val);
if (!ch)
warning(0, "Unknown Accept-Application field name 0x%02x.", val);
break;
default:
if (headername) {
warning(0, "Did not expect short-integer with "
"'%s' header, skipping.", headername);
}
break;
}
} else if (ret == WSP_FIELD_VALUE_DATA) {
switch (field_type) {
case WSP_HEADER_ACCEPT:
case WSP_HEADER_CONTENT_TYPE:
/* Content-general-form and Accept-general-form
* are defined separately in WSP, but their
* definitions are equivalent. */
decoded = wsp_unpack_accept_general_form(context);
break;
case WSP_HEADER_ACCEPT_CHARSET:
decoded = wsp_unpack_accept_charset_general_form(context);
break;
case WSP_HEADER_ACCEPT_LANGUAGE:
decoded = unpack_accept_language_general_form(context);
break;
case WSP_HEADER_AGE:
case WSP_HEADER_CONTENT_LENGTH:
case WSP_HEADER_MAX_FORWARDS:
case WSP_HEADER_BEARER_INDICATION:
case WSP_HEADER_ACCEPT_APPLICATION:
/* Long-integer version of Integer-value */
{
long l = unpack_multi_octet_integer(context,
parse_octets_left(context));
decoded = octstr_create("");
octstr_append_decimal(decoded, l);
}
break;
case WSP_HEADER_AUTHORIZATION:
decoded = unpack_credentials(context);
break;
case WSP_HEADER_PROXY_AUTHORIZATION:
decoded = proxy_unpack_credentials(context);
break;
case WSP_HEADER_CACHE_CONTROL:
decoded = unpack_cache_directive(context);
break;
case WSP_HEADER_CONTENT_MD5:
decoded = parse_get_octets(context,
parse_octets_left(context));
octstr_binary_to_base64(decoded);
/* Zap the CR LF sequence at the end */
octstr_delete(decoded, octstr_len(decoded) - 2, 2);
break;
case WSP_HEADER_CONTENT_RANGE:
decoded = unpack_content_range(context);
break;
case WSP_HEADER_DATE:
case WSP_HEADER_EXPIRES:
case WSP_HEADER_IF_MODIFIED_SINCE:
case WSP_HEADER_IF_RANGE:
case WSP_HEADER_IF_UNMODIFIED_SINCE:
case WSP_HEADER_LAST_MODIFIED:
/* Back up to get the length byte again */
parse_skip(context, -1);
decoded = wsp_unpack_date_value(context);
break;
case WSP_HEADER_PRAGMA:
/* The value is a bare Parameter, without a preceding
* header body. unpack_parameter wasn't really
* designed for this. We work around it here. */
decoded = octstr_create("");
if (unpack_parameter(context, decoded) < 0) {
octstr_destroy(decoded);
decoded = NULL;
} else {
/* Remove the leading "; " */
octstr_delete(decoded, 0, 2);
}
break;
case WSP_HEADER_PROXY_AUTHENTICATE:
case WSP_HEADER_WWW_AUTHENTICATE:
decoded = unpack_challenge(context);
break;
case WSP_HEADER_RANGE:
decoded = unpack_range_value(context);
break;
case WSP_HEADER_RETRY_AFTER:
decoded = unpack_retry_after(context);
break;
case WSP_HEADER_WARNING:
decoded = unpack_warning_value(context);
break;
case WSP_HEADER_CONTENT_DISPOSITION:
decoded = unpack_disposition(context);
break;
case WSP_HEADER_ENCODING_VERSION:
decoded = unpack_encoding_version(context);
break;
default:
if (headername) {
warning(0, "Did not expect value-length with "
"'%s' header, skipping.", headername);
}
break;
}
if (headername && parse_octets_left(context) > 0) {
warning(0, "WSP: %s: skipping %ld trailing octets.",
headername, parse_octets_left(context));
}
parse_skip_to_limit(context);
parse_pop_limit(context);
} else {
panic(0, "Unknown field-value type %d.", ret);
}
if (ch == NULL && decoded != NULL)
ch = (unsigned char *)octstr_get_cstr(decoded);
if (ch == NULL)
goto value_error;
if (!headername) {
warning(0, "Unknown header number 0x%02x.", field_type);
goto value_error;
}
http_header_add(unpacked, (char *)headername,(char *) ch);
octstr_destroy(decoded);
return;
value_error:
warning(0, "Skipping faulty header.");
octstr_destroy(decoded);
}
void wsp_unpack_app_header(List *unpacked, ParseContext *context)
{
Octstr *header = NULL;
Octstr *value = NULL;
header = parse_get_nul_string(context);
value = parse_get_nul_string(context);
if (header && value) {
http_header_add(unpacked, octstr_get_cstr(header),
octstr_get_cstr(value));
}
if (parse_error(context))
warning(0, "Error parsing application-header.");
octstr_destroy(header);
octstr_destroy(value);
}
List *wsp_headers_unpack(Octstr *headers, int content_type_present)
{
ParseContext *context;
int byte;
List *unpacked;
int code_page;
unpacked = http_create_empty_headers();
context = parse_context_create(headers);
if (octstr_len(headers) > 0) {
debug("wsp", 0, "WSP: decoding headers:");
octstr_dump(headers, 0);
}
if (content_type_present)
wsp_unpack_well_known_field(unpacked,
WSP_HEADER_CONTENT_TYPE, context);
code_page = 1; /* default */
while (parse_octets_left(context) > 0 && !parse_error(context)) {
byte = parse_get_char(context);
if (byte == 127 || (byte >= 1 && byte <= 31)) {
if (byte == 127)
code_page = parse_get_char(context);
else
code_page = byte;
if (code_page == 1)
info(0, "Returning to code page 1 (default).");
else {
warning(0, "Shift to unknown code page %d.",
code_page);
warning(0, "Will try to skip headers until "
"next known code page.");
}
} else if (byte >= 128) { /* well-known-header */
if (code_page == 1)
wsp_unpack_well_known_field(unpacked, byte - 128, context);
else {
debug("wsp", 0, "Skipping field 0x%02x.", byte);
wsp_skip_field_value(context);
}
} else if (byte > 31 && byte < 127) {
/* Un-parse the character we just read */
parse_skip(context, -1);
wsp_unpack_app_header(unpacked, context);
} else {
warning(0, "Unsupported token or header (start 0x%x)", byte);
break;
}
}
if (gwlist_len(unpacked) > 0) {
long i;
debug("wsp", 0, "WSP: decoded headers:");
for (i = 0; i < gwlist_len(unpacked); i++) {
Octstr *header = gwlist_get(unpacked, i);
debug("wsp", 0, "%s", octstr_get_cstr(header));
}
debug("wsp", 0, "WSP: End of decoded headers.");
}
parse_context_destroy(context);
return unpacked;
}
/**********************************************************************/
/* Start of header packing code (HTTP to WSP) */
/**********************************************************************/
static int pack_accept(Octstr *packet, Octstr *value);
static int pack_accept_charset(Octstr *packet, Octstr *value);
static int pack_accept_encoding(Octstr *packet, Octstr *value);
static int pack_accept_language(Octstr *packet, Octstr *value);
static int pack_cache_control(Octstr *packet, Octstr *value);
static int pack_challenge(Octstr *packet, Octstr *value);
static int pack_connection(Octstr *packet, Octstr *value);
static int pack_content_disposition(Octstr *packet, Octstr *value);
static int pack_content_range(Octstr *packet, Octstr *value);
static int pack_credentials(Octstr *packet, Octstr *value);
static int pack_encoding(Octstr *packet, Octstr *value);
static int pack_expires(Octstr *packet, Octstr *value);
static int pack_field_name(Octstr *packet, Octstr *value);
static int pack_if_range(Octstr *packet, Octstr *value);
static int pack_language(Octstr *packet, Octstr *value);
static int pack_md5(Octstr *packet, Octstr *value);
static int pack_method(Octstr *packet, Octstr *value);
static int pack_pragma(Octstr *packet, Octstr *value);
static int pack_range(Octstr *packet, Octstr *value);
static int pack_range_unit(Octstr *packet, Octstr *value);
static int pack_transfer_encoding(Octstr *packet, Octstr *value);
static int pack_uri(Octstr *packet, Octstr *value);
static int pack_warning(Octstr *packet, Octstr *value);
/* these are used in MMS encapsulation code too */
struct headerinfo headerinfo[] =
{
{ WSP_HEADER_ACCEPT, pack_accept, LIST },
{ WSP_HEADER_ACCEPT_CHARSET, pack_accept_charset, LIST },
{ WSP_HEADER_ACCEPT_ENCODING, pack_accept_encoding, LIST },
{ WSP_HEADER_ACCEPT_LANGUAGE, pack_accept_language, LIST },
{ WSP_HEADER_ACCEPT_RANGES, pack_range_unit, LIST },
{ WSP_HEADER_AGE, wsp_pack_integer_string, 0 },
/* pack_method is slightly too general because Allow is only
* supposed to encode well-known-methods. */
{ WSP_HEADER_ALLOW, pack_method, LIST },
{ WSP_HEADER_AUTHORIZATION, pack_credentials, BROKEN_LIST },
{ WSP_HEADER_CACHE_CONTROL, pack_cache_control, LIST },
{ WSP_HEADER_CACHE_CONTROL_V13, pack_cache_control, LIST },
{ WSP_HEADER_CACHE_CONTROL_V14, pack_cache_control, LIST },
{ WSP_HEADER_CONNECTION, pack_connection, LIST },
{ WSP_HEADER_CONTENT_BASE, pack_uri, 0 },
{ WSP_HEADER_CONTENT_ENCODING, pack_encoding, LIST },
{ WSP_HEADER_CONTENT_LANGUAGE, pack_language, LIST },
{ WSP_HEADER_CONTENT_LENGTH, wsp_pack_integer_string, 0 },
{ WSP_HEADER_CONTENT_LOCATION, pack_uri, 0 },
{ WSP_HEADER_CONTENT_MD5, pack_md5, 0 },
{ WSP_HEADER_CONTENT_RANGE, pack_content_range, 0 },
{ WSP_HEADER_CONTENT_TYPE, wsp_pack_content_type, 0 },
{ WSP_HEADER_DATE, wsp_pack_date, 0 },
{ WSP_HEADER_ETAG, wsp_pack_text, 0 },
{ WSP_HEADER_EXPIRES, pack_expires, 0 },
{ WSP_HEADER_FROM, wsp_pack_text, 0 },
{ WSP_HEADER_HOST, wsp_pack_text, 0 },
{ WSP_HEADER_IF_MODIFIED_SINCE, wsp_pack_date, 0 },
{ WSP_HEADER_IF_MATCH, wsp_pack_text, 0 },
{ WSP_HEADER_IF_NONE_MATCH, wsp_pack_text, 0 },
{ WSP_HEADER_IF_RANGE, pack_if_range, 0 },
{ WSP_HEADER_IF_UNMODIFIED_SINCE, wsp_pack_date, 0 },
{ WSP_HEADER_LAST_MODIFIED, wsp_pack_date, 0 },
{ WSP_HEADER_LOCATION, pack_uri, 0 },
{ WSP_HEADER_MAX_FORWARDS, wsp_pack_integer_string, 0 },
{ WSP_HEADER_PRAGMA, pack_pragma, LIST },
{ WSP_HEADER_PROXY_AUTHENTICATE, pack_challenge, BROKEN_LIST },
{ WSP_HEADER_PROXY_AUTHORIZATION, pack_credentials, BROKEN_LIST },
{ WSP_HEADER_PUBLIC, pack_method, LIST },
{ WSP_HEADER_RANGE, pack_range, 0 },
{ WSP_HEADER_REFERER, pack_uri, 0 },
{ WSP_HEADER_RETRY_AFTER, wsp_pack_retry_after, 0 },
{ WSP_HEADER_SERVER, wsp_pack_text, 0 },
{ WSP_HEADER_TRANSFER_ENCODING, pack_transfer_encoding, LIST },
{ WSP_HEADER_UPGRADE, wsp_pack_text, LIST },
{ WSP_HEADER_USER_AGENT, wsp_pack_text, 0 },
{ WSP_HEADER_VARY, pack_field_name, LIST },
{ WSP_HEADER_VIA, wsp_pack_text, LIST },
{ WSP_HEADER_WARNING, pack_warning, LIST },
{ WSP_HEADER_WWW_AUTHENTICATE, pack_challenge, BROKEN_LIST },
{ WSP_HEADER_CONTENT_DISPOSITION, pack_content_disposition, 0 },
{ WSP_HEADER_PUSH_FLAG, wsp_pack_integer_string, 0},
{ WSP_HEADER_X_WAP_CONTENT_URI, pack_uri, 0},
{ WSP_HEADER_X_WAP_INITIATOR_URI, pack_uri, 0},
{ WSP_HEADER_X_WAP_APPLICATION_ID, wsp_pack_integer_string, 0},
{ WSP_HEADER_CONTENT_ID, wsp_pack_quoted_text, 0},
{ WSP_HEADER_ENCODING_VERSION, wsp_pack_version_value, 0 }
// DAVI { WSP_HEADER_SET_COOKIE, pack_version_value, 0 }
};
static Parameter *parm_create(Octstr *key, Octstr *value)
{
Parameter *parm;
parm = gw_malloc(sizeof(*parm));
parm->key = key;
parm->value = value;
return parm;
}
static void parm_destroy(Parameter *parm)
{
if (parm == NULL)
return;
octstr_destroy(parm->key);
octstr_destroy(parm->value);
gw_free(parm);
}
void parm_destroy_item(void *parm)
{
parm_destroy(parm);
}
static Parameter *parm_parse(Octstr *value)
{
long pos;
Octstr *key, *val;
pos = octstr_search_char(value, '=', 0);
if (pos > 0) {
key = octstr_copy(value, 0, pos);
val = octstr_copy(value, pos + 1, octstr_len(value) - pos);
octstr_strip_blanks(key);
octstr_strip_blanks(val);
} else {
key = octstr_duplicate(value);
val = NULL;
}
return parm_create(key, val);
}
/* Many HTTP field elements can take parameters in a standardized
* form: parameters appear after the main value, each is introduced
* by a semicolon (;), and consists of a key=value pair or just
* a key, where the key is a token and the value is either a token
* or a quoted-string.
* The main value itself is a series of tokens, separators, and
* quoted-strings.
*
* This function will take such a field element, and remove all
* parameters from it. The parameters are returned as a List
* of Parameter, where the value field is left NULL
* if the parameter was just a key.
* It returns NULL if there were no parameters.
*/
List *wsp_strip_parameters(Octstr *value)
{
long pos;
long len;
int c;
long end;
List *parms;
long firstparm;
len = octstr_len(value);
/* Find the start of the first parameter. */
for (pos = 0; pos < len; pos++) {
c = octstr_get_char(value, pos);
if (c == ';')
break;
else if (c == '"')
pos += http_header_quoted_string_len(value, pos) - 1;
}
if (pos >= len)
return NULL; /* no parameters */
parms = gwlist_create();
firstparm = pos;
for (pos++; pos > 0 && pos < len; pos++) {
Octstr *key = NULL;
Octstr *val = NULL;
end = octstr_search_char(value, '=', pos);
if (end < 0)
end = octstr_search_char(value, ';', pos);
if (end < 0)
end = octstr_len(value);
key = octstr_copy(value, pos, end - pos);
octstr_strip_blanks(key);
pos = end;
if (octstr_get_char(value, pos) == '=') {
pos++;
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_get_char(value, pos) == '"')
end = pos + http_header_quoted_string_len(value, pos);
else
end = octstr_search_char(value, ';', pos);
if (end < 0)
end = octstr_len(value);
val = octstr_copy(value, pos, end - pos);
octstr_strip_blanks(val);
pos = end;
pos = octstr_search_char(value, ';', pos);
}
gwlist_append(parms, parm_create(key, val));
}
octstr_delete(value, firstparm, octstr_len(value) - firstparm);
octstr_strip_blanks(value);
return parms;
}
int wsp_pack_text(Octstr *packed, Octstr *text)
{
/* This check catches 0-length strings as well, because
* octstr_get_char will return -1. */
if (octstr_get_char(text, 0) >= 128 || octstr_get_char(text, 0) < 32)
octstr_append_char(packed, WSP_QUOTE);
octstr_append(packed, text);
octstr_append_char(packed, 0);
return 0;
}
/* Pack a string as quoted-text WAP WSP 203, Section 8.4.2.1 */
int wsp_pack_quoted_text(Octstr *packed, Octstr *text)
{
octstr_append_char(packed, '"');
octstr_append(packed,text);
octstr_append_char(packed,0);
return 0;
}
/* Pack text as Quoted-string if it starts with a " character.
* Pack it as Text-string otherwise. */
static void pack_quoted_string(Octstr *packed, Octstr *text)
{
octstr_append(packed, text);
if (octstr_get_char(text, octstr_len(text) - 1) == '"' &&
octstr_get_char(text, 0) == '"')
octstr_delete(packed, octstr_len(packed) - 1, 1);
octstr_append_char(packed, 0);
}
/* Is this char in the 'separators' set defined by HTTP? */
static int is_separator_char(int c)
{
switch (c) {
case '(':
case ')':
case '<':
case '>':
case '@':
case ',':
case ';':
case ':':
case '\\':
case '"':
case '/':
case '[':
case ']':
case '?':
case '=':
case '{':
case '}':
case 32: /* SP */
case 9: /* HT */
return 1;
default:
return 0;
}
}
/* Is this char part of a 'token' as defined by HTTP? */
static int is_token_char(int c)
{
return c >= 32 && c < 127 && !is_separator_char(c);
}
/* Is this string a 'token' as defined by HTTP? */
static int is_token(Octstr *token)
{
return octstr_len(token) > 0 &&
octstr_check_range(token, 0, octstr_len(token), is_token_char);
}
/* We represent qvalues as integers from 0 through 1000, rather than
* as floating values. */
static int parse_qvalue(Octstr *value)
{
int qvalue;
if (value == NULL)
return -1;
if (!isdigit(octstr_get_char(value, 0)))
return -1;
qvalue = (octstr_get_char(value, 0) - '0') * 1000;
if (octstr_get_char(value, 1) != '.')
goto gotvalue;
if (!isdigit(octstr_get_char(value, 2)))
goto gotvalue;
qvalue += (octstr_get_char(value, 2) - '0') * 100;
if (!isdigit(octstr_get_char(value, 3)))
goto gotvalue;
qvalue += (octstr_get_char(value, 3) - '0') * 10;
if (!isdigit(octstr_get_char(value, 4)))
goto gotvalue;
qvalue += (octstr_get_char(value, 4) - '0');
gotvalue:
if (qvalue < 0 || qvalue > 1000)
return -1;
return qvalue;
}
static int get_qvalue(List *parms, int default_qvalue)
{
long i;
Parameter *parm;
int qvalue;
for (i = 0; i < gwlist_len(parms); i++) {
parm = gwlist_get(parms, i);
if (octstr_str_compare(parm->key, "q") == 0 ||
octstr_str_compare(parm->key, "Q") == 0) {
qvalue = parse_qvalue(parm->value);
if (qvalue >= 0)
return qvalue;
}
}
return default_qvalue;
}
static int pack_qvalue(Octstr *packed, int qvalue)
{
/* "Quality factor 1 is the default value and shall never
* be sent." */
if (qvalue == 1000)
return -1;
/* Remember that our qvalues are already multiplied by 1000. */
if (qvalue % 10 == 0)
qvalue = qvalue / 10 + 1;
else
qvalue = qvalue + 100;
octstr_append_uintvar(packed, qvalue);
return 0;
}
/* Pack value as a Value-length followed by the encoded value. */
void wsp_pack_value(Octstr *packed, Octstr *encoded)
{
long len;
len = octstr_len(encoded);
if (len <= 30)
octstr_append_char(packed, len);
else {
octstr_append_char(packed, 31);
octstr_append_uintvar(packed, len);
}
octstr_append(packed, encoded);
}
void wsp_pack_long_integer(Octstr *packed, unsigned long integer)
{
long oldlen = octstr_len(packed);
unsigned char octet;
long len;
if (integer == 0) {
/* The Multi-octet-integer has to be at least 1 octet long. */
octstr_append_char(packed, 1); /* length */
octstr_append_char(packed, 0); /* value */
return;
}
/* Encode it back-to-front, by repeatedly inserting
* at the same position, because that's easier. */
for (len = 0; integer != 0; integer >>= 8, len++) {
octet = integer & 0xff;
octstr_insert_data(packed, oldlen, (char *)&octet, 1);
}
octet = len;
octstr_insert_data(packed, oldlen, (char *)&octet, 1);
}
void wsp_pack_short_integer(Octstr *packed, unsigned long integer)
{
gw_assert(integer <= MAX_SHORT_INTEGER);
octstr_append_char(packed, integer + 0x80);
}
void wsp_pack_integer_value(Octstr *packed, unsigned long integer)
{
if (integer <= MAX_SHORT_INTEGER)
wsp_pack_short_integer(packed, integer);
else
wsp_pack_long_integer(packed, integer);
}
int wsp_pack_integer_string(Octstr *packed, Octstr *value)
{
unsigned long integer;
long pos;
int c;
int digit;
integer = 0;
for (pos = 0; pos < octstr_len(value); pos++) {
c = octstr_get_char(value, pos);
if (!isdigit(c))
break;
digit = c - '0';
if (integer > ULONG_MAX / 10)
goto overflow;
integer *= 10;
if (integer > ULONG_MAX - digit)
goto overflow;
integer += digit;
}
wsp_pack_integer_value(packed, integer);
return 0;
overflow:
warning(0, "WSP: Number too large to handle: '%s'.",
octstr_get_cstr(value));
return -1;
}
int wsp_pack_version_value(Octstr *packed, Octstr *version)
{
long major, minor;
long pos;
pos = octstr_parse_long(&major, version, 0, 10);
if (pos < 0 || major < 1 || major > 7)
goto usetext;
if (pos == octstr_len(version))
minor = 15;
else {
if (octstr_get_char(version, pos) != '.')
goto usetext;
pos = octstr_parse_long(&minor, version, pos + 1, 10);
if (pos != octstr_len(version) || minor < 0 || minor > 14)
goto usetext;
}
wsp_pack_short_integer(packed, major << 4 | minor);
return 0;
usetext:
wsp_pack_text(packed, version);
return 0;
}
int wsp_pack_constrained_value(Octstr *packed, Octstr *text, long value)
{
if (value >= 0)
wsp_pack_short_integer(packed, value);
else
wsp_pack_text(packed, text);
return 0;
}
static void pack_parameter(Octstr *packed, Parameter *parm)
{
long keytoken;
long tmp;
long start;
start = octstr_len(packed);
/* Parameter = Typed-parameter | Untyped-parameter */
/* keytoken = wsp_string_to_parameter(parm->key); */
/* XXX this should obey what kind of WSP Encoding-Version the client is using */
keytoken = wsp_string_to_versioned_parameter(parm->key, WSP_1_2);
if (keytoken >= 0) {
/* Typed-parameter = Well-known-parameter-token Typed-value */
/* Well-known-parameter-token = Integer-value */
wsp_pack_integer_value(packed, keytoken);
/* Typed-value = Compact-value | Text-value */
/* First try to pack as Compact-value or No-value.
* If that fails, pack as Text-value. */
if (parm->value == NULL) {
octstr_append_char(packed, 0); /* No-value */
return;
} else switch (keytoken) {
case 0: /* q */
tmp = parse_qvalue(parm->value);
if (tmp >= 0) {
if (pack_qvalue(packed, tmp) < 0)
octstr_delete(packed, start,
octstr_len(packed) - start);
return;
}
break;
case 1: /* charset */
tmp = wsp_string_to_charset(parm->value);
if (tmp >= 0) {
wsp_pack_integer_value(packed, tmp);
return;
}
break;
case 2: /* level */
wsp_pack_version_value(packed, parm->value);
return;
case 3: /* type */
if (octstr_check_range(parm->value, 0,
octstr_len(parm->value),
gw_isdigit) &&
wsp_pack_integer_string(packed, parm->value) >= 0)
return;
break;
case 5: /* name */
case 6: /* filename */
break;
case 7: /* differences */
if (pack_field_name(packed, parm->value) >= 0)
return;
break;
case 8: /* padding */
if (octstr_parse_long(&tmp, parm->value, 0, 10)
== octstr_len(parm->value) &&
tmp >= 0 && tmp <= MAX_SHORT_INTEGER) {
wsp_pack_short_integer(packed, tmp);
return;
}
break;
}
pack_quoted_string(packed, parm->value);
} else {
/* Untyped-parameter = Token-text Untyped-value */
wsp_pack_text(packed, parm->key);
/* Untyped-value = Integer-value | Text-value */
if (parm->value == NULL) {
octstr_append_char(packed, 0); /* No-value */
return;
}
/* If we can pack as integer, do so. */
if (octstr_parse_long(&tmp, parm->value, 0, 10)
== octstr_len(parm->value)) {
wsp_pack_integer_value(packed, tmp);
} else {
pack_quoted_string(packed, parm->value);
}
}
}
void wsp_pack_parameters(Octstr *packed, List *parms)
{
long i;
Parameter *parm;
for (i = 0; i < gwlist_len(parms); i++) {
parm = gwlist_get(parms, i);
pack_parameter(packed, parm);
}
}
static int pack_uri(Octstr *packed, Octstr *value)
{
wsp_pack_text(packed, value);
return 0;
}
static int pack_md5(Octstr *packed, Octstr *value)
{
Octstr *binary;
binary = octstr_duplicate(value);
octstr_base64_to_binary(binary);
if (octstr_len(binary) != 16) {
error(0, "WSP: MD5 value not 128 bits.");
return -1;
}
octstr_append_char(packed, 16);
octstr_append(packed, binary);
octstr_destroy(binary);
return 0;
}
/* Actually packs a "Value-length Challenge" */
/* Relies on http_split_auth_value to have converted the entry to
* the normal HTTP parameter format rather than the comma-separated
* one used by challenge and credentials. */
static int pack_challenge(Octstr *packed, Octstr *value)
{
Octstr *encoding = NULL;
Octstr *scheme = NULL;
Octstr *basic = octstr_imm("Basic");
Octstr *realm = octstr_imm("realm");
Octstr *parmstring = NULL;
List *parms = NULL;
Parameter *realmparm = NULL;
long realmpos = -1;
Octstr *realmval = NULL;
long pos;
encoding = octstr_create("");
/* Get authentication scheme */
for (pos = 0; pos < octstr_len(value); pos++) {
if (!is_token_char(octstr_get_char(value, pos)))
break;
}
scheme = octstr_copy(value, 0, pos);
octstr_strip_blanks(scheme);
/* Skip whitespace */
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_case_compare(scheme, basic) == 0) {
parmstring = octstr_copy(value, pos, octstr_len(value) - pos);
realmparm = parm_parse(parmstring);
octstr_append_char(encoding, BASIC_AUTHENTICATION);
realmpos = octstr_len(encoding);
} else {
long i;
wsp_pack_text(encoding, scheme);
realmpos = octstr_len(encoding);
/* Find the realm parameter and exclude it */
parms = wsp_strip_parameters(value);
for (i = 0; i < gwlist_len(parms); i++) {
Parameter *parm = gwlist_get(parms, i);
if (octstr_case_compare(realm, parm->key) == 0) {
realmparm = parm;
gwlist_delete(parms, i, 1);
break;
}
}
wsp_pack_parameters(encoding, parms);
}
/*
* In the WSP encoding we have to put the realm value first, but
* with non-Basic challenges we don't know if it will come first
* in the HTTP header. So we just start parsing parameters, and
* go back and insert the realm value later. The same technique
* is used for Basic authentication to simplify the code.
*/
if (realmparm == NULL ||
octstr_case_compare(realmparm->key, realm) != 0 ||
realmparm->value == NULL)
goto error;
/* Zap quote marks */
if (octstr_get_char(realmparm->value, 0) == '"' &&
octstr_get_char(realmparm->value, octstr_len(realmparm->value) - 1) == '"') {
octstr_delete(realmparm->value, 0, 1);
octstr_delete(realmparm->value, octstr_len(realmparm->value) - 1, 1);
}
gw_assert(realmpos >= 0);
realmval = octstr_create("");
wsp_pack_text(realmval, realmparm->value);
octstr_insert(encoding, realmval, realmpos);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
octstr_destroy(scheme);
octstr_destroy(parmstring);
parm_destroy(realmparm);
gwlist_destroy(parms, parm_destroy_item);
octstr_destroy(realmval);
return 0;
error:
warning(0, "WSP: Cannot parse challenge.");
octstr_destroy(encoding);
octstr_destroy(scheme);
octstr_destroy(parmstring);
parm_destroy(realmparm);
gwlist_destroy(parms, parm_destroy_item);
octstr_destroy(realmval);
return -1;
}
/* Actually packs a "Value-length Credentials" */
/* Relies on http_split_auth_value to have converted the entry to
* the normal HTTP parameter format rather than the comma-separated
* one used by challenge and credentials. */
static int pack_credentials(Octstr *packed, Octstr *value)
{
Octstr *encoding = NULL;
Octstr *scheme = NULL;
Octstr *basic = NULL;
long pos;
encoding = octstr_create("");
/* Get authentication scheme */
for (pos = 0; pos < octstr_len(value); pos++) {
if (!is_token_char(octstr_get_char(value, pos)))
break;
}
scheme = octstr_copy(value, 0, pos);
octstr_strip_blanks(scheme);
/* Skip whitespace */
while (isspace(octstr_get_char(value, pos)))
pos++;
basic = octstr_imm("Basic");
if (octstr_case_compare(scheme, basic) == 0) {
Octstr *cookie;
Octstr *userid;
Octstr *password;
octstr_append_char(encoding, BASIC_AUTHENTICATION);
cookie = octstr_copy(value, pos, octstr_len(value) - pos);
octstr_base64_to_binary(cookie);
pos = octstr_search_char(cookie, ':', 0);
if (pos < 0) {
warning(0, "WSP: bad cookie in credentials '%s'.",
octstr_get_cstr(value));
octstr_destroy(cookie);
goto error;
}
userid = octstr_copy(cookie, 0, pos);
password = octstr_copy(cookie, pos + 1, octstr_len(cookie) - pos);
wsp_pack_text(encoding, userid);
wsp_pack_text(encoding, password);
octstr_destroy(cookie);
octstr_destroy(userid);
octstr_destroy(password);
} else {
List *parms;
wsp_pack_text(encoding, scheme);
parms = wsp_strip_parameters(value);
wsp_pack_parameters(encoding, parms);
gwlist_destroy(parms, parm_destroy_item);
}
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
octstr_destroy(scheme);
return 0;
error:
octstr_destroy(encoding);
octstr_destroy(scheme);
return -1;
}
int wsp_pack_date(Octstr *packed, Octstr *value)
{
long timeval;
/* If we get a negative timeval here, this means either
* we're beyond the time_t 32 bit int positive border for the
* timestamp or we're really handling time before epoch. */
timeval = date_parse_http(value);
if (timeval == -1) {
warning(0, "WSP headers: cannot decode date '%s'",
octstr_get_cstr(value));
return -1;
}
/* We'll assume that we don't package time before epoch. */
wsp_pack_long_integer(packed, (unsigned long) timeval);
return 0;
}
static int pack_connection(Octstr *packed, Octstr *value)
{
return wsp_pack_constrained_value(packed, value,
wsp_string_to_connection(value));
}
static int pack_encoding(Octstr *packed, Octstr *value)
{
return wsp_pack_constrained_value(packed, value,
wsp_string_to_encoding(value));
}
static int pack_field_name(Octstr *packed, Octstr *value)
{
/* XXX we need to obey which WSP encoding-version to use */
/* return pack_constrained_value(packed, value,
wsp_string_to_header(value)); */
return wsp_pack_constrained_value(packed, value,
wsp_string_to_versioned_header(value, WSP_1_2));
}
static int pack_language(Octstr *packed, Octstr *value)
{
long language;
/* Can't use pack_constrained_value here because
* language does not necessarily fit in a Short-integer. */
language = wsp_string_to_language(value);
if (language >= 0)
wsp_pack_integer_value(packed, language);
else
wsp_pack_text(packed, value);
return 0;
}
/* Encode value as Well-known-method | Token-text */
static int pack_method(Octstr *packed, Octstr *value)
{
/* In the future, we will need some way to refer to extended
* method names negotiated for this session. */
return wsp_pack_constrained_value(packed, value,
wsp_string_to_method(value));
}
/* Encode value as Accept-ranges-value */
static int pack_range_unit(Octstr *packed, Octstr *value)
{
return wsp_pack_constrained_value(packed, value,
wsp_string_to_ranges(value));
}
/* Encode byte-range-spec | suffix-byte-range-spec as Range-value.
* Return position after the parsed spec. */
static int pack_range_value(Octstr *packed, Octstr *value, long pos)
{
long first_byte_pos;
long last_byte_pos;
long suffix_length;
Octstr *encoding;
while (isspace(octstr_get_char(value, pos)))
pos++;
if (isdigit(octstr_get_char(value, pos))) {
/* byte-range-spec */
pos = octstr_parse_long(&first_byte_pos, value, pos, 10);
if (pos < 0 || first_byte_pos < 0)
return -1;
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_get_char(value, pos) != '-')
return -1;
pos++;
while (isspace(octstr_get_char(value, pos)))
pos++;
if (isdigit(octstr_get_char(value, pos))) {
pos = octstr_parse_long(&last_byte_pos, value, pos, 10);
if (pos < 0 || last_byte_pos < 0)
return -1;
} else {
last_byte_pos = -1;
}
encoding = octstr_create("");
octstr_append_char(encoding, BYTE_RANGE);
octstr_append_uintvar(encoding, first_byte_pos);
if (last_byte_pos >= 0)
octstr_append_uintvar(encoding, last_byte_pos);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
} else if (octstr_get_char(value, pos) == '-') {
/* suffix-byte-range-spec */
pos++;
pos = octstr_parse_long(&suffix_length, value, pos, 10);
if (pos < 0 || suffix_length < 0)
return -1;
encoding = octstr_create("");
octstr_append_char(encoding, SUFFIX_BYTE_RANGE);
octstr_append_uintvar(encoding, suffix_length);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
} else
return -1;
return pos;
}
static int pack_transfer_encoding(Octstr *packed, Octstr *value)
{
return wsp_pack_constrained_value(packed, value,
wsp_string_to_transfer_encoding(value));
}
/* Also used by pack_content_type */
static int pack_accept(Octstr *packed, Octstr *value)
{
List *parms;
long media;
parms = wsp_strip_parameters(value);
/* XXX we need to obey which WSP encoding-version to use */
/* media = wsp_string_to_content_type(value); */
media = wsp_string_to_versioned_content_type(value, WSP_1_2);
/* See if we can fit this in a Constrained-media encoding */
if (parms == NULL && media <= MAX_SHORT_INTEGER) {
wsp_pack_constrained_value(packed, value, media);
} else {
Octstr *encoding = octstr_create("");
if (media >= 0)
wsp_pack_integer_value(encoding, media);
else
wsp_pack_text(encoding, value);
wsp_pack_parameters(encoding, parms);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
}
gwlist_destroy(parms, parm_destroy_item);
return 0;
}
static int pack_accept_charset(Octstr *packed, Octstr *value)
{
List *parms;
long charset;
long qvalue;
parms = wsp_strip_parameters(value);
charset = wsp_string_to_charset(value);
qvalue = 1000;
if (parms)
qvalue = get_qvalue(parms, qvalue);
gwlist_destroy(parms, parm_destroy_item);
/* See if we can fit this in a Constrained-charset encoding */
if (qvalue == 1000 && charset <= MAX_SHORT_INTEGER) {
wsp_pack_constrained_value(packed, value, charset);
} else {
Octstr *encoding = octstr_create("");
if (charset >= 0)
wsp_pack_integer_value(encoding, charset);
else
wsp_pack_text(encoding, value);
if (qvalue != 1000)
pack_qvalue(encoding, qvalue);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
}
return 0;
}
/* WSP 8.4.2.9 does not specify any way to encode parameters for
* an Accept-encoding field, but RFC2616 allows q parameters.
* We'll have to simplify: qvalue > 0 means encode it, qvalue == 0
* means don't encode it.
*/
static int pack_accept_encoding(Octstr *packed, Octstr *value)
{
List *parms;
int qvalue;
qvalue = 1000; /* default */
parms = wsp_strip_parameters(value);
if (parms)
qvalue = get_qvalue(parms, qvalue);
gwlist_destroy(parms, parm_destroy_item);
if (qvalue > 0) {
if (qvalue < 1000)
warning(0, "Cannot encode q-value in Accept-Encoding.");
pack_encoding(packed, value);
} else {
warning(0, "Cannot encode q=0 in Accept-Encoding; skipping this encoding.");
return -1;
}
return 0;
}
static int pack_accept_language(Octstr *packed, Octstr *value)
{
List *parms;
long language;
long qvalue;
parms = wsp_strip_parameters(value);
language = wsp_string_to_language(value);
qvalue = 1000;
if (parms)
qvalue = get_qvalue(parms, qvalue);
gwlist_destroy(parms, parm_destroy_item);
/* See if we can fit this in a Constrained-language encoding. */
/* Note that our language table already includes Any-language */
if (qvalue == 1000 && language <= MAX_SHORT_INTEGER) {
wsp_pack_constrained_value(packed, value, language);
} else {
Octstr *encoding = octstr_create("");
if (language >= 0)
wsp_pack_integer_value(encoding, language);
else
wsp_pack_text(encoding, value);
if (qvalue != 1000)
pack_qvalue(encoding, qvalue);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
}
return 0;
}
static int pack_cache_control(Octstr *packed, Octstr *value)
{
Parameter *parm;
long tmp;
parm = parm_parse(value);
if (parm->value == NULL) {
wsp_pack_constrained_value(packed, value,
wsp_string_to_cache_control(parm->key));
} else {
Octstr *encoding = octstr_create("");
tmp = wsp_string_to_cache_control(parm->key);
if (tmp < 0) {
/* According to WSP 8.4.2.15, the format
* is "Cache-extension Parameter", and
* Cache-extension is a Token-text.
* But in HTTP a cache-extension is of
* the form token=value, which maps
* nicely to Parameter. So what is
* this extra Token-text? I decided to leave it blank.
* - Richard Braakman
*/
wsp_pack_text(encoding, octstr_imm(""));
pack_parameter(encoding, parm);
} else {
int done = 0;
Octstr *value_encoding;
List *names;
Octstr *element;
value_encoding = octstr_create("");
switch (tmp) {
case WSP_CACHE_CONTROL_NO_CACHE:
case WSP_CACHE_CONTROL_PRIVATE:
if (octstr_get_char(parm->value, 0) == '"')
octstr_delete(parm->value, 0, 1);
if (octstr_get_char(parm->value, octstr_len(parm->value) - 1) == '"')
octstr_delete(parm->value, octstr_len(parm->value) - 1, 1);
names = http_header_split_value(parm->value);
while ((element = gwlist_consume(names))) {
pack_field_name(value_encoding, element);
octstr_destroy(element);
}
gwlist_destroy(names, octstr_destroy_item);
done = 1;
break;
case WSP_CACHE_CONTROL_MAX_AGE:
case WSP_CACHE_CONTROL_MAX_STALE:
case WSP_CACHE_CONTROL_MIN_FRESH:
if (wsp_pack_integer_string(value_encoding, parm->value) >= 0)
done = 1;
break;
}
if (done) {
wsp_pack_short_integer(encoding, tmp);
octstr_append(encoding, value_encoding);
} else {
/* See note above */
pack_parameter(encoding, parm);
}
octstr_destroy(value_encoding);
}
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
}
parm_destroy(parm);
return 1;
}
static int pack_content_disposition(Octstr *packed, Octstr *value)
{
List *parms;
long disposition;
parms = wsp_strip_parameters(value);
disposition = wsp_string_to_disposition(value);
if (disposition >= 0) {
Octstr *encoding = octstr_create("");
wsp_pack_short_integer(encoding, disposition);
wsp_pack_parameters(encoding, parms);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
} else {
warning(0, "WSP: Cannot encode Content-Disposition '%s'.",
octstr_get_cstr(value));
goto error;
}
gwlist_destroy(parms, parm_destroy_item);
return 0;
error:
gwlist_destroy(parms, parm_destroy_item);
return -1;
}
static int pack_content_range(Octstr *packed, Octstr *value)
{
Octstr *bytes;
long pos;
long firstbyte, lastbyte, instancelen;
Octstr *encoding;
bytes = octstr_imm("bytes ");
if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0)
goto error;
pos = octstr_len(bytes);
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_get_char(value, pos) == '*')
goto warning;
pos = octstr_parse_long(&firstbyte, value, pos, 10);
if (pos < 0)
goto error;
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_get_char(value, pos++) != '-')
goto error;
pos = octstr_parse_long(&lastbyte, value, pos, 10);
if (pos < 0)
goto error;
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_get_char(value, pos++) != '/')
goto error;
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_get_char(value, pos) == '*')
goto warning;
pos = octstr_parse_long(&instancelen, value, pos, 10);
if (pos < 0)
goto error;
/* XXX: If the range is valid but not representable,
* or if it's invalid, then should we refrain from sending
* anything at all? It might pollute the client's cache. */
if (lastbyte < firstbyte || instancelen < lastbyte) {
warning(0, "WSP: Content-Range '%s' is invalid.",
octstr_get_cstr(value));
return -1;
}
encoding = octstr_create("");
octstr_append_uintvar(encoding, firstbyte);
octstr_append_uintvar(encoding, instancelen);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
return 0;
error:
warning(0, "WSP: Cannot parse Content-Range '%s'.",
octstr_get_cstr(value));
return -1;
warning:
warning(0, "WSP: Cannot encode Content-Range '%s'.",
octstr_get_cstr(value));
return -1;
}
int wsp_pack_content_type(Octstr *packed, Octstr *value)
{
/* The expansion of Content-type-value works out to be
* equivalent to Accept-value. */
return pack_accept(packed, value);
}
static int pack_expires(Octstr *packed, Octstr *value)
{
int ret;
ret = wsp_pack_date(packed, value);
if (ret < 0) {
/* Responses with an invalid Expires header should be treated
as already expired. If we just skip this header, then the client
won't know that. So we encode one with a date far in the past. */
wsp_pack_long_integer(packed, LONG_AGO_VALUE);
ret = 0;
}
return ret;
}
static int pack_if_range(Octstr *packed, Octstr *value)
{
if (octstr_get_char(value, 0) == '"' ||
(octstr_get_char(value, 0) == 'W' &&
octstr_get_char(value, 1) == '/')) {
return wsp_pack_text(packed, value); /* It's an etag */
} else {
return wsp_pack_date(packed, value);
}
}
static int pack_pragma(Octstr *packed, Octstr *value)
{
Octstr *nocache;
nocache = octstr_imm("no-cache");
if (octstr_case_compare(value, nocache) == 0)
wsp_pack_short_integer(packed, WSP_CACHE_CONTROL_NO_CACHE);
else {
Parameter *parm;
Octstr *encoding;
encoding = octstr_create("");
parm = parm_parse(value);
pack_parameter(encoding, parm);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
parm_destroy(parm);
}
return 0;
}
static int pack_range(Octstr *packed, Octstr *value)
{
Octstr *bytes = octstr_imm("bytes");
long pos;
if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0
|| is_token_char(octstr_get_char(value, octstr_len(bytes))))
goto error;
pos = octstr_len(bytes);
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_get_char(value, pos) != '=')
goto error;
pos++;
for (;;) {
/* Discard the whole header if any part of it can't be
* parsed. Probably a partial Range header is worse
* than none at all. */
pos = pack_range_value(packed, value, pos);
if (pos < 0)
goto error;
while (isspace(octstr_get_char(value, pos)))
pos++;
if (octstr_get_char(value, pos) != ',')
break;
pos++;
wsp_pack_short_integer(packed, WSP_HEADER_RANGE);
}
return 0;
error:
warning(0, "WSP: Cannot parse 'Range: %s'.",
octstr_get_cstr(value));
return -1;
}
/* The value is either a HTTP-date or a delta-seconds (integer). */
int wsp_pack_retry_after(Octstr *packed, Octstr *value)
{
Octstr *encoded = NULL;
encoded = octstr_create("");
if (isdigit(octstr_get_char(value, 0))) {
octstr_append_char(encoded, RELATIVE_TIME);
if (wsp_pack_integer_string(encoded, value) < 0)
goto error;
} else {
octstr_append_char(encoded, ABSOLUTE_TIME);
if (wsp_pack_date(encoded, value) < 0)
goto error;
}
wsp_pack_value(packed, encoded);
octstr_destroy(encoded);
return 0;
error:
octstr_destroy(encoded);
return -1;
}
static int convert_rfc2616_warning_to_rfc2068(int warn_code)
{
int i;
struct {
int rfc2616code;
int rfc2068code;
} code_transform[] = {
{ 110, 10 }, /* Response is stale */
{ 111, 11 }, /* Revalidation failed */
{ 112, 12 }, /* Disconnected operation */
{ 113, 13 }, /* Heuristic expiration */
{ 199, 99 }, /* Miscellaneous warning */
{ 214, 14 }, /* Transformation applied */
{ 299, 99 }, /* Miscellaneous (persistent) warning */
{ -1, -1 }
};
for (i = 0; code_transform[i].rfc2616code >= 0; i++) {
if (code_transform[i].rfc2616code == warn_code)
return code_transform[i].rfc2068code;
}
return warn_code; /* conversion failed */
}
static int pack_warning(Octstr *packed, Octstr *value)
{
long warn_code = -1;
Octstr *warn_agent = NULL;
Octstr *warn_text = NULL;
long pos;
long start;
pos = octstr_parse_long(&warn_code, value, 0, 10);
if (pos < 0 || warn_code < 0)
goto error;
if (warn_code > 99) {
/* RFC2068 uses 2-digit codes, and RFC2616 uses 3-digit codes.
* This must be an RFC2616 code. We don't have room in the
* encoding for such codes, so we try to convert it back to
* an RFC2068 code. */
warn_code = convert_rfc2616_warning_to_rfc2068(warn_code);
}
if (warn_code > MAX_SHORT_INTEGER) {
warning(0, "WSP: Cannot encode warning code %ld.", warn_code);
return -1;
}
while (isspace(octstr_get_char(value, pos)))
pos++;
start = pos;
while (pos < octstr_len(value) && !isspace(octstr_get_char(value, pos)))
pos++;
if (pos > start)
warn_agent = octstr_copy(value, start, pos - start);
while (isspace(octstr_get_char(value, pos)))
pos++;
start = pos;
pos += http_header_quoted_string_len(value, pos);
if (pos > start)
warn_text = octstr_copy(value, start, pos - start);
if (warn_agent == NULL && warn_text == NULL) {
/* Simple encoding */
wsp_pack_short_integer(packed, warn_code);
} else {
/* General encoding */
Octstr *encoding = octstr_create("");
if (warn_agent == NULL)
warn_agent = octstr_create("");
if (warn_text == NULL)
warn_text = octstr_create("");
wsp_pack_short_integer(encoding, warn_code);
wsp_pack_text(encoding, warn_agent);
wsp_pack_text(encoding, warn_text);
wsp_pack_value(packed, encoding);
octstr_destroy(encoding);
}
octstr_destroy(warn_agent);
octstr_destroy(warn_text);
return 0;
error:
warning(0, "WSP: Cannot parse 'Warning: %s'.",
octstr_get_cstr(value));
octstr_destroy(warn_agent);
octstr_destroy(warn_text);
return -1;
}
void wsp_pack_separate_content_type(Octstr *packed, List *headers)
{
Octstr *content_type;
/* Can't use http_header_get_content_type because it
* does not parse all possible parameters. */
content_type = http_header_find_first(headers, "Content-Type");
if (content_type == NULL) {
warning(0, "WSP: Missing Content-Type header in "
"response, guessing application/octet-stream");
content_type = octstr_create("application/octet-stream");
}
octstr_strip_blanks(content_type);
wsp_pack_content_type(packed, content_type);
octstr_destroy(content_type);
}
int wsp_pack_list(Octstr *packed, long fieldnum, List *elements, int i)
{
long startpos;
Octstr *element;
while ((element = gwlist_consume(elements))) {
startpos = octstr_len(packed);
wsp_pack_short_integer(packed, fieldnum);
if (headerinfo[i].func(packed, element) < 0) {
/* Remove whatever we added */
octstr_delete(packed, startpos,
octstr_len(packed) - startpos);
/* But continue processing elements */
}
octstr_destroy(element);
}
return 0;
}
static int pack_known_header(Octstr *packed, long fieldnum, Octstr *value)
{
List *elements = NULL;
long startpos;
long i;
octstr_strip_blanks(value);
startpos = octstr_len(packed);
for (i = 0; i < TABLE_SIZE(headerinfo); i++) {
if (headerinfo[i].header == fieldnum)
break;
}
if (i == TABLE_SIZE(headerinfo)) {
error(0, "WSP: Do not know how to encode header type %ld",
fieldnum);
goto error;
}
if (headerinfo[i].allows_list == LIST)
elements = http_header_split_value(value);
else if (headerinfo[i].allows_list == BROKEN_LIST)
elements = http_header_split_auth_value(value);
else
elements = NULL;
if (elements != NULL) {
if (wsp_pack_list(packed, fieldnum, elements, i) < 0)
goto error;
} else {
wsp_pack_short_integer(packed, fieldnum);
if (headerinfo[i].func(packed, value) < 0)
goto error;
}
gwlist_destroy(elements, octstr_destroy_item);
return 0;
error:
/* Remove whatever we added */
octstr_delete(packed, startpos, octstr_len(packed) - startpos);
gwlist_destroy(elements, octstr_destroy_item);
return -1;
}
int wsp_pack_application_header(Octstr *packed,
Octstr *fieldname, Octstr *value)
{
if (!is_token(fieldname)) {
warning(0, "WSP headers: `%s' is not a valid HTTP token.",
octstr_get_cstr(fieldname));
return -1;
}
/* We have to deal specially with the X-WAP.TOD header, because it
* is the only case of a text-format header defined with a non-text
* field value. */
/* Normally this should be a case-insensitive comparison, but this
* header will only be present if we generated it ourselves in the
* application layer. */
if (octstr_str_compare(fieldname, "X-WAP.TOD") == 0) {
wsp_pack_text(packed, fieldname);
return wsp_pack_date(packed, value);
}
wsp_pack_text(packed, fieldname);
wsp_pack_text(packed, value);
return 0;
}
Octstr *wsp_headers_pack(List *headers, int separate_content_type, int wsp_version)
{
Octstr *packed;
long i, len;
int errors;
packed = octstr_create("");
if (separate_content_type)
wsp_pack_separate_content_type(packed, headers);
len = gwlist_len(headers);
for (i = 0; i < len; i++) {
Octstr *fieldname;
Octstr *value;
long fieldnum;
http_header_get(headers, i, &fieldname, &value);
/* XXX we need to obey which WSP encoding-version to use */
/* fieldnum = wsp_string_to_header(fieldname); */
fieldnum = wsp_string_to_versioned_header(fieldname, wsp_version);
errors = 0;
if (separate_content_type && fieldnum == WSP_HEADER_CONTENT_TYPE) {
/* already handled */
} else if (fieldnum < 0) {
if (wsp_pack_application_header(packed, fieldname, value) < 0)
errors = 1;
} else {
if (pack_known_header(packed, fieldnum, value) < 0)
errors = 1;
}
if (errors)
warning(0, "Skipping header: %s: %s",
octstr_get_cstr(fieldname),
octstr_get_cstr(value));
octstr_destroy(fieldname);
octstr_destroy(value);
}
/*
http_header_dump(headers);
octstr_dump(packed, 0);
*/
return packed;
}
gateway-1.4.3/wap/wtp_init_machine.def 0000644 0001750 0001750 00000011647 11132672002 017011 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_init_machine.def: macro call for generating WTP initiator state
* machine. See the architecture document for guidance how to use and update
* it.
*
* By Aarno Syvnen for Wapit Ltd.
*
* WTPRespMachine data structure includes current state of WTP responder state
* machine for a specific transaction. This means all data needed to handle at
* least two incoming events of a certain transaction. Its fields can be
* grouped following way:
*
* General: a) wtp initiator machine state
* b) tidnew flag, telling whether tid is wrapped up
*
* Fields telling the service required:
* a) transaction class (is transaction confirmed or not)
* b) user acknowledgement flag (do we wait for response
* primitive of WTP user (for instance, WSP) or not)
*
* Machine identification: address four-tuple and transaction identifier
*
* Fields required for reliable transmission:
* a) pointer to the timer of this machine in the timers list
* b) counter for retransmissions
* c) flag telling are we resending ack pdu doing tid verifica-
* tion or not
* d) packed invoke message, for greater effectivity
*/
#if !defined(MACHINE)
#error "Macro MACHINE is missing."
#elif !defined(INTEGER)
#error "Macro INTEGER is missing."
#elif !defined(ENUM)
#error "Macro ENUM is missing."
#elif !defined(EVENT)
#error "Macro EVENT is missing."
#elif !defined(TIMER)
#error "Macro TIMER is missing."
#elif !defined(ADDRTUPLE)
#error "Macro ADDRTUPLE is missing."
#endif
MACHINE(ENUM(state)
INTEGER(tid) /* transaction identifier */
ADDRTUPLE(addr_tuple)
INTEGER(tidnew) /* tidnew flag */
INTEGER(u_ack) /* user acknowledgement flag */
EVENT(invoke) /* invoke datagram for resending */
TIMER(timer)
INTEGER(rcr) /* retransmission counter */
INTEGER(tidok_sent) /* are we resending tid verification */
INTEGER(rid) /* are we resending invoke */
)
#undef MACHINE
#undef ENUM
#undef EVENT
#undef INTEGER
#undef ADDRTUPLE
#undef TIMER
gateway-1.4.3/wap/wsp_push_client.h 0000644 0001750 0001750 00000007206 11132672002 016363 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_push_client.h: push client (for testing) interface
*
* By Aarno Syvnen for Wapit Ltd.
*/
#ifndef WSP_PUSH_CLIENT_H
#define WSP_PUSH_CLIENT_H
typedef struct WSPPushClientMachine WSPPushClientMachine;
#include "gwlib/gwlib.h"
#include "wap_addr.h"
#include "wap_events.h"
#include "wap.h"
/*
* Push client states
*/
enum push_client_states {
#define PUSH_CLIENT_STATE_NAME(state) state,
#define ROW(state, event, condition, action, next_state)
#include "wsp_push_client_states.def"
push_client_states_count
};
typedef enum push_client_states push_client_states;
/*
* Declaration of push client state machine. We define one macro for every
* separate type.
*/
struct WSPPushClientMachine {
long cpid;
#define INTEGER(name) long name;
#define HTTPHEADERS(name) List *name;
#define OCTSTR(name) Octstr *name;
#define MACHINE(fields) fields
#include "wsp_push_client_machine.def"
};
#endif
gateway-1.4.3/wap/wsp_pdu.def 0000644 0001750 0001750 00000012332 11132672002 015141 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
PDU(Connect, "...",
TYPE(8, 1)
UINT(version, "WSP protocol version", 8)
UINTVAR(capabilities_len, "Length of capabilities")
UINTVAR(headers_len, "Length of session headers")
OCTSTR(capabilities, "Requested capabilities", capabilities_len)
OCTSTR(headers, "Session headers", headers_len)
, 1)
PDU(ConnectReply, "...",
TYPE(8, 2)
UINTVAR(sessionid, "Session ID")
UINTVAR(capabilities_len, "Length of capabilities")
UINTVAR(headers_len, "Length of session headers")
OCTSTR(capabilities, "Accepted capabilities", capabilities_len)
OCTSTR(headers, "Session headers", headers_len)
, 1)
PDU(Redirect, "Problem: need REPEAT structure to parse addresses",
TYPE(8, 3)
UINT(permanent, "Permanent Redirect flag", 1)
UINT(reuse_security, "Reuse Security Session flag", 1)
RESERVED(6)
REST(addresses, "Redirect addresses")
, 1)
PDU(Disconnect, "...",
TYPE(8, 5)
UINTVAR(sessionid, "Session ID")
, 1)
PDU(Get, "...",
TYPE(4, 0x4)
UINT(subtype, "GET, OPTIONS, HEAD, DELETE, or TRACE", 4)
UINTVAR(uri_len, "Length of URI")
OCTSTR(uri, "URI", uri_len)
REST(headers, "Request headers")
, p->subtype <= 4)
PDU(Post, "...",
TYPE(4, 0x6)
UINT(subtype, "POST or PUT", 4)
UINTVAR(uri_len, "Length of URI")
UINTVAR(headers_len, "Length of headers")
OCTSTR(uri, "URI", uri_len)
OCTSTR(headers, "Content type and request headers", headers_len)
REST(data, "Request data")
, p->subtype <= 1)
PDU(Reply, "...",
TYPE(8, 4)
UINT(status, "Status code", 8)
UINTVAR(headers_len, "Length of headers")
OCTSTR(headers, "Content type and reply headers", headers_len)
REST(data, "Reply data")
, 1)
PDU(Push, "...",
TYPE(8, 6)
UINTVAR(headers_len, "Length of headers")
OCTSTR(headers, "Content type and headers", headers_len)
REST(data, "Push data")
, 1)
PDU(ConfirmedPush, "...",
TYPE(8, 7)
UINTVAR(headers_len, "Length of headers")
OCTSTR(headers, "Content type and headers", headers_len)
REST(data, "Push data")
, 1)
PDU(Suspend, "...",
TYPE(8, 8)
UINTVAR(sessionid, "Session ID")
, 1)
PDU(Resume, "...",
TYPE(8, 9)
UINTVAR(sessionid, "Session ID")
UINTVAR(capabilities_len, "Length of capabilities")
OCTSTR(capabilities, "Reserved capabilities field", capabilities_len)
REST(headers, "Session headers")
, 1)
PDU(sia, "...",
UINT(version, "sia version", 8)
UINTVAR(appidlist_len, "Length of application id list")
OCTSTR(application_id_list, "application id list", appidlist_len)
UINTVAR(contactpoints_len, "Length of contact point list")
OCTSTR(contactpoints, "list of contact points", contactpoints_len)
, 1)
gateway-1.4.3/wap/wap.c 0000644 0001750 0001750 00000007626 11132672004 013747 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wap.c - Generic functions for wap library
*/
#include "gwlib/gwlib.h"
#include "wap.h"
#include "wtp.h"
#define CONNECTIONLESS_PORT 9200
void wap_dispatch_datagram(WAPEvent *dgram)
{
gw_assert(dgram != NULL);
if (dgram->type != T_DUnitdata_Ind) {
warning(0, "wap_dispatch_datagram got event of unexpected type.");
wap_event_dump(dgram);
wap_event_destroy(dgram);
return;
}
/* XXX Assumption does not hold for client side */
if (dgram->u.T_DUnitdata_Ind.addr_tuple->local->port == CONNECTIONLESS_PORT) {
wsp_unit_dispatch_event(dgram);
} else {
List *events;
events = wtp_unpack_wdp_datagram(dgram);
if (!events) {
debug("wap.wap", 0, "ignoring truncated datagram");
wap_event_dump(dgram);
wap_event_destroy(dgram);
return;
}
while (gwlist_len(events) > 0) {
WAPEvent *event;
event = gwlist_extract_first(events);
if (wtp_event_is_for_responder(event))
wtp_resp_dispatch_event(event);
else
wtp_initiator_dispatch_event(event);
}
wap_event_destroy(dgram);
gwlist_destroy(events, NULL);
}
}
gateway-1.4.3/wap/cookies.c 0000644 0001750 0001750 00000042057 11132672002 014607 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* Module: cookies.c
*
* Description: Implements a minimal cookie handler for session persistence.
*
* References: RFC 2109
*
* Author: Paul Keogh, ANAM Wireless Internet Solutions
*
* Date: May 2000
*/
#include
#include
#include "gwlib/gwlib.h"
#include "wsp.h"
#include "cookies.h"
/* Statics */
static Octstr *get_header_value(Octstr*);
static Cookie *parse_cookie(Octstr*);
static void add_cookie_to_cache(const WSPMachine*, Cookie*);
static void expire_cookies(List*);
static void cookie_destroy(void*);
static int have_cookie(List*, Cookie*);
static int parse_http_date(const char*);
static Cookie emptyCookie;
Cookie *cookie_create(void)
{
Cookie *p;
p = gw_malloc(sizeof(Cookie)); /* Never returns NULL */
*p = emptyCookie;
p -> max_age = -1;
time (&p -> birth);
return p;
}
void cookies_destroy(List *cookies)
{
gwlib_assert_init();
if (cookies == NULL)
return;
gwlist_destroy(cookies, cookie_destroy);
}
int get_cookies(List *headers, const WSPMachine *sm)
{
Octstr *header = NULL;
Octstr *value = NULL;
Cookie *cookie = NULL;
long pos = 0;
/*
* This can happen if the user aborts while the HTTP request is pending from the server.
* In that case, the session machine is destroyed and is not available to this function
* for cookie caching.
*/
if (sm == NULL) {
info (0, "No session machine for cookie retrieval");
return 0;
}
for (pos = 0; pos < gwlist_len(headers); pos++) {
header = gwlist_get(headers, pos);
/* debug ("wap.wsp.http", 0, "get_cookies: Examining header (%s)", octstr_get_cstr (header)); */
if (strncasecmp ("set-cookie", octstr_get_cstr (header),10) == 0) {
debug ("wap.wsp.http", 0, "Caching cookie (%s)", octstr_get_cstr (header));
if ((value = get_header_value (header)) == NULL) {
error (0, "get_cookies: No value in (%s)", octstr_get_cstr(header));
continue;
}
/* Parse the received cookie */
if ((cookie = parse_cookie(value)) != NULL) {
/* Check to see if this cookie is already present */
if (have_cookie(sm->cookies, cookie) == 1) {
debug("wap.wsp.http", 0, "parse_cookie: Cookie present");
cookie_destroy(cookie);
continue;
} else {
add_cookie_to_cache(sm, cookie);
debug("wap.wsp.http", 0, "get_cookies: Added (%s)",
octstr_get_cstr(cookie -> name));
}
}
}
}
debug("wap.wsp.http", 0, "get_cookies: End");
return 0;
}
int set_cookies(List *headers, WSPMachine *sm)
{
Cookie *value = NULL;
Octstr *cookie = NULL;
long pos = 0;
if (headers == NULL || sm == NULL) {
error (0, "set_cookies: Null argument(s) - no headers, WSPMachine or both");
return -1;
}
/* Expire cookies that have timed out */
expire_cookies(sm->cookies);
/* Walk through the cookie cache, adding the cookie to the request headers */
if (gwlist_len(sm->cookies) > 0) {
debug("wap.wsp.http", 0, "set_cookies: Cookies in cache");
for (pos = 0; pos < gwlist_len(sm->cookies); pos++) {
value = gwlist_get(sm->cookies, pos);
cookie = octstr_create("Cookie: ");
if (value->version)
octstr_append(cookie, value->version);
octstr_append(cookie, value->name);
octstr_append_char(cookie, '=');
octstr_append(cookie, value->value);
if (value->path) {
octstr_append_char(cookie, ';');
octstr_append(cookie, value->path);
}
if (value->domain) {
octstr_append_char(cookie, ';');
octstr_append(cookie, value->domain);
}
gwlist_append(headers, cookie);
debug("wap.wsp.http", 0, "set_cookies: Added (%s)", octstr_get_cstr (cookie));
}
} else
debug("wap.wsp.http", 0, "set_cookies: No cookies in cache");
return 0;
}
/*
* Private interface functions
*/
/*
* Function: get_header_value
*
* Description: Gets the header value as an Octstr.
*/
static Octstr *get_header_value(Octstr *header)
{
Octstr *h = NULL;
long colon = -1;
if (header == NULL) {
error(0, "get_header_value: NULL argument");
return NULL;
}
octstr_strip_blanks(header);
colon = octstr_search_char(header, ':', 0);
if (colon == -1) {
error(0, "get_header_value: Malformed header (%s)", octstr_get_cstr (header));
return NULL;
} else {
h = octstr_copy(header, colon + 1, octstr_len(header));
octstr_strip_blanks(h);
}
debug("wap.wsp.http", 0, "get_header_value: Value (%s)", octstr_get_cstr (h));
return h;
}
/*
* Function: parse_cookie
*
* Description: Parses the received cookie and rewrites it for sending.
*/
static Cookie *parse_cookie(Octstr *cookiestr)
{
char *v = NULL;
char *p = NULL;
int delta = 0;
Cookie *c = NULL;
Octstr **f = NULL;
if (cookiestr == NULL) {
error(0, "parse_cookie: NULL argument");
return NULL;
}
v = gw_strdup(octstr_get_cstr (cookiestr));
p = strtok(v, ";");
c = cookie_create(); /* Never returns NULL */
while (p != NULL) {
while (isspace((int)*p)) p++; /* Skip leading whitespace */
if (strncasecmp("version", p, 7) == 0)
f = &c -> version;
else if (strncasecmp("path", p, 4) == 0)
f = &c -> path;
else if (strncasecmp("domain", p, 6) == 0)
f = &c -> domain; /* XXX DAVI: Shouldn't we check if domain is similar
* to real domain, and to set domain to
* real domain if not set by header ??? */
else if (strncasecmp("max-age", p, 7) == 0) {
c -> max_age = atol(strrchr (p, '=') + 1);
p = strtok(NULL, ";");
continue;
}
else if (strncasecmp("expires", p, 7) == 0) {
delta = parse_http_date(p);
if (delta != -1)
c->max_age = delta;
p = strtok(NULL, ";");
continue;
}
else if (strncasecmp("comment", p, 7) == 0 ) { /* Ignore comments */
p = strtok(NULL, ";");
continue;
}
else if (strncasecmp("secure", p, 6) == 0 ) { /* XXX DAVI: this should processed */
p = strtok(NULL, ";");
continue;
}
else { /* Name value pair - this should be first */
char *equals = NULL;
if ((equals = strrchr(p, '=')) != NULL) {
*equals = '\0';
c->name = octstr_create(p);
c->value = octstr_create(equals + 1);
} else {
error(0, "parse_cookie: Bad name=value cookie component (%s)", p);
cookie_destroy(c);
return NULL;
}
p = strtok(NULL, ";");
continue;
}
if (*f != NULL) { /* Undefined behaviour - 4.2.2 */
error(0, "parse_cookie: Duplicate cookie field (%s), discarding", p);
p = strtok(NULL, ";");
continue;
}
*f = octstr_create("$");
octstr_append_cstr(*f, p);
p = strtok(NULL, ";");
}
/* Process version - 4.3.4
* XXX DAVI: Altough it seems to be "MUST" in RFC, no one sends a Version
* tag when it's value is "0"
if (c->version == NULL) {
c->version = octstr_create("");
octstr_append_cstr(c->version, "$Version=\"0\";");
}
*/
gw_free (v);
return c;
}
/*
* Function: add_cookie_to_cache
*
* Description: Adds the cookie to the WSPMachine cookie cache.
*/
static void add_cookie_to_cache(const WSPMachine *sm, Cookie *value)
{
gw_assert(sm != NULL);
gw_assert(sm->cookies != NULL);
gw_assert(value != NULL);
gwlist_append(sm->cookies, value);
return;
}
/*
* Function: have_cookie
*
* Description: Checks to see if the cookie is present in the list.
*/
static int have_cookie(List *cookies, Cookie *cookie)
{
Cookie *value = NULL;
long pos = 0;
if (cookies == NULL || cookie == NULL) {
error(0, "have_cookie: Null argument(s) - no Cookie list, Cookie or both");
return 0;
}
/* Walk through the cookie cache, comparing cookie */
while (pos < gwlist_len(cookies)) {
value = gwlist_get(cookies, pos);
/* octstr_compare() now only returns 0 on an exact match or if both args are 0 */
debug ("wap.wsp.http", 0, "have_cookie: Comparing name (%s:%s), path (%s:%s), domain (%s:%s)",
octstr_get_cstr(cookie->name), octstr_get_cstr(value->name),
octstr_get_cstr(cookie->path), octstr_get_cstr(value->path),
octstr_get_cstr(cookie->domain), octstr_get_cstr(value->domain));
/* Match on no value or value and value equality for name, path and domain */
if (
(value->name == NULL ||
((value->name != NULL && cookie->name != NULL) && octstr_compare(value->name, cookie->name) == 0)) &&
(value->path == NULL ||
((value->path != NULL && cookie->path != NULL) && octstr_compare(value->path, cookie->path) == 0)) &&
(value->domain == NULL ||
((value->domain != NULL && cookie->domain != NULL) && octstr_compare(value->domain, cookie->domain) == 0))
) {
/* We have a match according to 4.3.3 - discard the old one */
cookie_destroy(value);
gwlist_delete(cookies, pos, 1);
/* Discard the new cookie also if max-age is 0 - set if expiry date is up */
if (cookie->max_age == 0) {
debug("wap.wsp.http", 0, "have_cookie: Discarding expired cookie (%s)",
octstr_get_cstr(cookie->name));
return 1;
}
debug("wap.wsp.http", 0, "have_cookie: Updating cached cookie (%s)",
octstr_get_cstr (cookie->name));
break;
} else {
pos++;
}
}
return 0;
}
/*
* Function: expire_cookies
*
* Description: Walks thru the cookie list and checking for expired cookies.
*/
static void expire_cookies(List *cookies)
{
Cookie *value = NULL;
time_t now = 0;
long pos = 0;
if (cookies == NULL) {
error(0, "expire_cookies: Null argument(s) - no Cookie list");
return;
}
/* Walk through the cookie cache */
time(&now);
if (gwlist_len(cookies) > 0) {
debug("wap.wsp.http", 0, "expire_cookies: Cookies in cache");
for (pos = 0; pos < gwlist_len(cookies); pos++) {
value = gwlist_get(cookies, pos);
gw_assert(value != NULL);
if (value->max_age != -1) { /* Interesting value */
if (value->max_age + value->birth < now) {
debug("wap.wsp.http", 0, "expire_cookies: Expired cookie (%s)",
octstr_get_cstr(value->name));
cookie_destroy(value);
gwlist_delete(cookies, pos, 1);
}
}
}
} else
debug("wap.wsp.http", 0, "expire_cookies: No cookies in cache");
return;
}
static void cookie_destroy(void *p)
{
Cookie *cookie;
if (p == NULL)
return;
cookie = p;
octstr_destroy(cookie->name);
octstr_destroy(cookie->value);
octstr_destroy(cookie->version);
octstr_destroy(cookie->domain);
octstr_destroy(cookie->path);
gw_free(cookie);
debug("wap.wsp.http", 0, "cookie_destroy: Destroyed cookie");
return;
}
/*
* Function: parse_http_date
*
* Description: Parses an HTTP date format as used by the Expires: header. See RFC 2616
* section 3.3.1 for more information.
* HTTP applications have historically allowed three different formats
* for the representation of date/time stamps:
*
* Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
* Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
* Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
*
* The first format is preferred as an Internet standard and represents
* a fixed-length subset of that defined by RFC 1123 [8] (an update to
* RFC 822 [9]). The second format is in common use, but is based on the
* obsolete RFC 850 [12] date format and lacks a four-digit year.
* HTTP/1.1 clients and servers that parse the date value MUST accept
* all three formats (for compatibility with HTTP/1.0), though they MUST
* only generate the RFC 1123 format for representing HTTP-date values
* in header fields.
*
* Returns: -1 on success, max-age sematic value on success.
*/
/*
* TODO: This is obviously the same as gwlib/date.c:date_http_parse().
* Need to unify this to one pulic function.
*/
static const char* months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
};
static int month_index(const char *s)
{
const char **p = &months[0];
int i = 0;
while (*p != NULL) {
if (strcmp(s, *p) == 0)
return i;
p++, i++;
}
return -1;
}
static int parse_http_date(const char *expires)
{
struct tm ti;
char *p = NULL;
char *date = NULL;
char month[MAX_HTTP_DATE_LENGTH];
time_t rv;
time_t now;
memset(&ti, 0, sizeof(struct tm));
/* Break up the Expires: header */
if (!(date = strchr(expires, '='))) {
error(0, "parse_http_date: Bogus expires type=value header (%s)", expires);
return -1;
} else {
date++;
while (isspace((int)*date))
++date;
}
/* Onto the date value */
if (!(p = strchr (date,' '))) {
error(0, "parse_http_date: Bogus date string (%s)", date);
return -1;
} else
while (isspace((int)*p))
++p;
if (MAX_HTTP_DATE_LENGTH < strlen(p)) {
error(0, "parse_http_date: %s blows length limit (%d)", date, MAX_HTTP_DATE_LENGTH);
return -1;
}
if (isalpha((int)*p)) {
/* ctime */
sscanf(p, (strstr(p, "DST") ? "%s %d %d:%d:%d %*s %d" : "%s %d %d:%d:%d %d"),
month, &ti.tm_mday, &ti.tm_hour, &ti.tm_min,
&ti.tm_sec, &ti.tm_year);
ti.tm_year -= 1900;
} else if (p[2] == '-') {
/* RFC 850 (normal HTTP) */
char buf[MAX_HTTP_DATE_LENGTH];
sscanf(p, "%s %d:%d:%d", buf, &ti.tm_hour, &ti.tm_min, &ti.tm_sec);
buf[2] = '\0';
ti.tm_mday = atoi(buf);
buf[6] = '\0';
strcpy(month, &buf[3]);
ti.tm_year = atoi(&buf[7]);
/* Prevent wraparound from ambiguity */
if (ti.tm_year < 70) {
ti.tm_year += 100;
} else if (ti.tm_year > 1900) {
ti.tm_year -= 1900;
}
} else {
/* RFC 822 */
sscanf(p,"%d %s %d %d:%d:%d",&ti.tm_mday, month, &ti.tm_year,
&ti.tm_hour, &ti.tm_min, &ti.tm_sec);
/*
* since tm_year is years since 1900 and the year we parsed
* is absolute, we need to subtract 1900 years from it
*/
ti.tm_year -= 1900;
}
ti.tm_mon = month_index(month);
if (ti.tm_mon == -1) {
error(0, "parse_http_date () failed on bad month value (%s)", month);
return -1;
}
ti.tm_isdst = -1;
rv = gw_mktime(&ti);
if (ti.tm_isdst)
rv -= 3600;
if (rv == -1) {
error(0, "parse_http_date(): mktime() was unable to resolve date/time: %s",
asctime(&ti));
return -1;
}
debug("parse_http_date", 0, "Parsed date (%s) as: %s", date, asctime(&ti));
/*
* If rv is valid, it should be some time in the (near) future. Normalise this to
* a max-age semantic so we can use the same expiry mechanism
*/
now = time(NULL);
if (rv - now < 0) {
/* This is bad - set the delta to 0 so we expire next time around */
error(0, "parse_http_date () Expiry time (%s) (delta=%ld) is in the past !",
asctime(&ti), rv-now);
return 0;
}
return rv - now;
}
gateway-1.4.3/wap/wsp_pdu.c 0000644 0001750 0001750 00000024032 11132672003 014626 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wsp_pdu.c - pack and unpack WSP packets
*
* Generates packing and unpacking code from wsp_pdu.def.
* Code is very similar to wsp_pdu.c, please make any changes in both files.
*
* Richard Braakman
*/
#include "gwlib/gwlib.h"
#include "wsp_pdu.h"
WSP_PDU *wsp_pdu_create(int type) {
WSP_PDU *pdu;
pdu = gw_malloc(sizeof(*pdu));
pdu->type = type;
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: {\
struct name *p; p = &pdu->u.name; \
fields \
} break;
#define UINT(field, docstring, bits) p->field = 0;
#define UINTVAR(field, docstring) p->field = 0;
#define OCTSTR(field, docstring, lengthfield) p->field = NULL;
#define REST(field, docstring) p->field = NULL;
#define TYPE(bits, value)
#define RESERVED(bits)
#include "wsp_pdu.def"
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
panic(0, "Internal error: Unknown PDU type %d", pdu->type);
break;
}
return pdu;
}
void wsp_pdu_destroy(WSP_PDU *pdu) {
if (pdu == NULL)
return;
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: {\
struct name *p; p = &pdu->u.name; \
fields \
} break;
#define UINT(field, docstring, bits)
#define UINTVAR(field, docstring)
#define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field);
#define REST(field, docstring) octstr_destroy(p->field);
#define TYPE(bits, value)
#define RESERVED(bits)
#include "wsp_pdu.def"
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
panic(0, "Cannot destroy unknown WSP PDU type %d", pdu->type);
break;
}
gw_free(pdu);
}
/* Determine which type of PDU this is, using the TYPE macros in
* the definition file. */
static int wsp_pdu_type(Octstr *data) {
long bitpos;
long lastpos = -1;
long lastnumbits = -1;
long lastval = -1;
int thistype;
/* This code looks slow, but an optimizing compiler will
* reduce it considerably. gcc -O2 will produce a single
* call to octstr_get_bits, folllowed by a sequence of
* tests on lastval. */
/* Only UINT and RESERVED fields may precede the TYPE */
#define PDU(name, docstring, fields, is_valid) \
bitpos = 0; \
thistype = name; \
fields
#define UINT(field, docstring, bits) bitpos += (bits);
#define UINTVAR(field, docstring)
#define OCTSTR(field, docstring, lengthfield)
#define REST(field, docstring)
#define TYPE(bits, value) \
if ((bits) != lastnumbits || bitpos != lastpos) { \
lastval = octstr_get_bits(data, bitpos, (bits)); \
} \
if (lastval == (value)) \
return thistype; \
lastnumbits = (bits); \
lastpos = bitpos;
#define RESERVED(bits) bitpos += (bits);
#include "wsp_pdu.def"
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
return -1;
}
WSP_PDU *wsp_pdu_unpack(Octstr *data) {
WSP_PDU *pdu = NULL;
long bitpos = 0;
gw_assert(data != NULL);
pdu = gw_malloc(sizeof(*pdu));
pdu->type = wsp_pdu_type(data);
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: { \
struct name *p = &pdu->u.name; \
fields \
gw_assert(bitpos % 8 == 0); \
if (bitpos / 8 != octstr_len(data)) { \
warning(0, "Bad length for " #name " PDU, " \
"expected %ld", bitpos / 8); \
} \
if (!(is_valid)) { \
warning(0, #name " PDU failed %s", #is_valid); \
} \
} break;
#define UINT(field, docstring, bits) \
p->field = octstr_get_bits(data, bitpos, (bits)); \
bitpos += (bits);
#define UINTVAR(field, docstring) \
gw_assert(bitpos % 8 == 0); \
p->field = octstr_get_bits(data, bitpos + 1, 7); \
while (octstr_get_bits(data, bitpos, 1)) { \
bitpos += 8; \
p->field <<= 7; \
p->field |= octstr_get_bits(data, bitpos + 1, 7); \
} \
bitpos += 8;
#define OCTSTR(field, docstring, lengthfield) \
gw_assert(bitpos % 8 == 0); \
p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \
bitpos += 8 * p->lengthfield;
#define REST(field, docstring) \
gw_assert(bitpos % 8 == 0); \
if (bitpos / 8 <= octstr_len(data)) { \
p->field = octstr_copy(data, bitpos / 8, \
octstr_len(data) - bitpos / 8); \
bitpos = octstr_len(data) * 8; \
} else { \
p->field = octstr_create(""); \
}
#define TYPE(bits, value) bitpos += (bits);
#define RESERVED(bits) bitpos += (bits);
#include "wsp_pdu.def"
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
warning(0, "WSP PDU with unknown type %d", pdu->type);
gw_free(pdu);
return NULL;
}
return pdu;
}
static void fixup_length_fields(WSP_PDU *pdu) {
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: { \
struct name *p; p = &pdu->u.name; \
fields \
} break;
#define UINT(field, docstring, bits)
#define UINTVAR(field, docstring)
#define OCTSTR(field, docstring, lengthfield) \
p->lengthfield = octstr_len(p->field);
#define REST(field, docstring)
#define TYPE(bits, value)
#define RESERVED(bits)
#include "wsp_pdu.def"
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
}
}
Octstr *wsp_pdu_pack(WSP_PDU *pdu) {
Octstr *data;
long bitpos;
/* We rely on octstr_set_bits to lengthen our octstr as needed. */
data = octstr_create("");
fixup_length_fields(pdu);
bitpos = 0;
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: { \
struct name *p = &pdu->u.name; \
fields \
gw_assert(bitpos % 8 == 0); \
} break;
#define UINT(field, docstring, bits) \
octstr_set_bits(data, bitpos, (bits), p->field); \
bitpos += (bits);
#define UINTVAR(field, docstring) \
gw_assert(bitpos % 8 == 0); \
octstr_append_uintvar(data, p->field); \
bitpos = 8 * octstr_len(data);
#define OCTSTR(field, docstring, lengthfield) \
gw_assert(bitpos % 8 == 0); \
if (p->field != NULL) \
octstr_append(data, p->field); \
bitpos += 8 * octstr_len(p->field);
#define REST(field, docstring) \
gw_assert(bitpos % 8 == 0); \
if (p->field != NULL) \
octstr_append(data, p->field); \
bitpos += 8 * octstr_len(p->field);
#define TYPE(bits, value) \
octstr_set_bits(data, bitpos, (bits), (value)); \
bitpos += (bits);
#define RESERVED(bits) bitpos += (bits);
#include "wsp_pdu.def"
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
panic(0, "Packing unknown WSP PDU type %ld", (long) pdu->type);
}
return data;
}
void wsp_pdu_dump(WSP_PDU *pdu, int level) {
char *dbg = "wap.wsp";
switch (pdu->type) {
#define PDU(name, docstring, fields, is_valid) \
case name: { \
struct name *p = &pdu->u.name; \
debug(dbg, 0, "%*sWSP %s PDU at %p:", \
level, "", #name, (void *)pdu); \
fields \
} break;
#define UINT(field, docstring, bits) \
debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
#define UINTVAR(field, docstring) \
debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
#define OCTSTR(field, docstring, lengthfield) \
debug(dbg, 0, "%*s %s:", level, "", docstring); \
octstr_dump(p->field, level + 1);
#define REST(field, docstring) \
debug(dbg, 0, "%*s %s:", level, "", docstring); \
octstr_dump(p->field, level + 1);
#define TYPE(bits, value)
#define RESERVED(bits)
#include "wsp_pdu.def"
#undef RESERVED
#undef TYPE
#undef REST
#undef OCTSTR
#undef UINTVAR
#undef UINT
#undef PDU
default:
debug(dbg, 0, "%*sWSP PDU at %p:", level, "", (void *)pdu);
debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
break;
}
debug("wap.wsp", 0, "%*sWSP PDU dump ends.", level, "");
}
gateway-1.4.3/wap/wtp_init.h 0000644 0001750 0001750 00000007323 11132672002 015012 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* WTP initiator header
*
* Aarno Syvnen for Wapit Ltd
*/
#ifndef WTP_INIT_H
#define WTP_INIT_H
#include "gwlib/gwlib.h"
#include "wap_addr.h"
#include "wap_events.h"
#include "timers.h"
/*
* Initiator machine states and initiator WTP machine.
* See included file for comments. Note that we must define macro
* ROW to produce an empty string.
*/
enum init_states {
#define INIT_STATE_NAME(state) state,
#define ROW(state, event, condition, action, next_state)
#include "wtp_init_states.def"
init_states_count
};
typedef enum init_states init_states;
/*
* See included file for comments. We define one macro for
* every separate type.
*/
typedef struct WTPInitMachine {
unsigned long mid;
#define INTEGER(name) int name;
#define EVENT(name) WAPEvent *name;
#define TIMER(name) Timer *name;
#define ADDRTUPLE(name) WAPAddrTuple *name;
#define ENUM(name) init_states name;
#define MACHINE(field) field
#include "wtp_init_machine.def"
} WTPInitMachine;
#endif
gateway-1.4.3/wap/wtp_pdu.def 0000644 0001750 0001750 00000011447 11132672003 015151 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
PDU(Invoke, "...",
UINT(con, "Continue flag (CON)", 1)
TYPE(4, 1)
UINT(gtr, "Group trailer (GTR)", 1)
UINT(ttr, "Transmission trailer (TTR)", 1)
UINT(rid, "Re-transmission indicator (RID)", 1)
UINT(tid, "Transaction ID (TID)", 16)
UINT(version, "WTP protocol version", 2)
UINT(tidnew, "TIDnew flag", 1)
UINT(uack, "User ack flag", 1)
RESERVED(2)
UINT(class, "Transaction class (TCL)", 2)
TPI(con)
REST(user_data, "Payload")
, p->class <= 2)
PDU(Result, "...",
UINT(con, "Continue flag (CON)", 1)
TYPE(4, 2)
UINT(gtr, "Group trailer (GTR)", 1)
UINT(ttr, "Transmission trailer (TTR)", 1)
UINT(rid, "Re-transmission indicator (RID)", 1)
UINT(tid, "Transaction ID (TID)", 16)
TPI(con)
REST(user_data, "Payload")
, 1)
PDU(Ack, "...",
UINT(con, "Continue flag (CON)", 1)
TYPE(4, 3)
UINT(tidverify, "TID verify / TID OK flag", 1)
RESERVED(1)
UINT(rid, "Re-transmission indicator (RID)", 1)
UINT(tid, "Transaction ID (TID)", 16)
TPI(con)
, 1)
PDU(Abort, "...",
UINT(con, "Continue flag (CON)", 1)
TYPE(4, 4)
UINT(abort_type, "Abort type", 3)
UINT(tid, "Transaction ID (TID)", 16)
UINT(abort_reason, "Abort reason", 8)
TPI(con)
, p->abort_type <= 1)
PDU(Segmented_invoke, "...",
UINT(con, "Continue flag (CON)", 1)
TYPE(4, 5)
UINT(gtr, "Group trailer (GTR)", 1)
UINT(ttr, "Transmission trailer (TTR)", 1)
UINT(rid, "Re-transmission indicator (RID)", 1)
UINT(tid, "Transaction ID (TID)", 16)
UINT(psn, "Packet sequence number", 8)
TPI(con)
REST(user_data, "Payload")
, 1)
PDU(Segmented_result, "...",
UINT(con, "Continue flag (CON)", 1)
TYPE(4, 6)
UINT(gtr, "Group trailer (GTR)", 1)
UINT(ttr, "Transmission trailer (TTR)", 1)
UINT(rid, "Re-transmission indicator (RID)", 1)
UINT(tid, "Transaction ID (TID)", 16)
UINT(psn, "Packet sequence number", 8)
TPI(con)
REST(user_data, "Payload")
, 1)
PDU(Negative_ack, "...",
UINT(con, "Continue flag (CON)", 1)
TYPE(4, 7)
RESERVED(2)
UINT(rid, "Re-transmission indicator (RID)", 1)
UINT(tid, "Transaction ID (TID)", 16)
UINT(nmissing, "Number of missing packets", 8)
OCTSTR(missing, "Missing packet PSNs", nmissing)
TPI(con)
, 1)
gateway-1.4.3/wap/wsp_server_method_states.def 0000644 0001750 0001750 00000030302 11132672003 020600 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp_server_method_states.def
*
* Macro calls to generate rows of the state table. See the documentation for
* guidance how to use and update these.
*
* Note that the `NULL' state has been renamed to `NULL_METHOD' because
* NULL is reserved by C.
*/
STATE_NAME(NULL_METHOD)
STATE_NAME(HOLDING)
STATE_NAME(REQUESTING)
STATE_NAME(PROCESSING)
STATE_NAME(REPLYING)
/* MISSING: TR_Invoke.ind, N_Methods == MOM */
ROW(NULL_METHOD,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Get,
{
List *headers;
WAPEvent *invoke;
int method;
Octstr *method_name;
/* Prepare the MethodInvoke here, because we have all
* the information nicely available. */
if (octstr_len(pdu->u.Get.headers) > 0)
headers = wsp_headers_unpack(pdu->u.Get.headers, 0);
else
headers = NULL;
invoke = wap_event_create(S_MethodInvoke_Ind);
invoke->u.S_MethodInvoke_Ind.server_transaction_id =
msm->transaction_id;
method = GET_METHODS + pdu->u.Get.subtype;
method_name = wsp_method_to_string(method);
if (method_name == NULL)
method_name = octstr_format("UNKNOWN%02X", method);
invoke->u.S_MethodInvoke_Ind.method = method_name;
invoke->u.S_MethodInvoke_Ind.request_uri =
octstr_duplicate(pdu->u.Get.uri);
invoke->u.S_MethodInvoke_Ind.request_headers = headers;
invoke->u.S_MethodInvoke_Ind.request_body = NULL;
invoke->u.S_MethodInvoke_Ind.session_headers =
http_header_duplicate(sm->http_headers);
invoke->u.S_MethodInvoke_Ind.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
invoke->u.S_MethodInvoke_Ind.client_SDU_size =
sm->client_SDU_size;
invoke->u.S_MethodInvoke_Ind.session_id =
msm->session_id;
msm->invoke = invoke;
},
HOLDING)
ROW(NULL_METHOD,
TR_Invoke_Ind,
e->tcl == 2 && pdu->type == Post,
{
List *headers;
WAPEvent *invoke;
int method;
Octstr *method_name;
/* Prepare the MethodInvoke here, because we have all
* the information nicely available. */
if (octstr_len(pdu->u.Post.headers) > 0)
headers = wsp_headers_unpack(pdu->u.Post.headers, 1);
else
headers = NULL;
invoke = wap_event_create(S_MethodInvoke_Ind);
invoke->u.S_MethodInvoke_Ind.server_transaction_id =
msm->transaction_id;
method = POST_METHODS + pdu->u.Get.subtype;
method_name = wsp_method_to_string(method);
if (method_name == NULL)
method_name = octstr_format("UNKNOWN%02X", method);
invoke->u.S_MethodInvoke_Ind.method = method_name;
invoke->u.S_MethodInvoke_Ind.request_uri =
octstr_duplicate(pdu->u.Post.uri);
invoke->u.S_MethodInvoke_Ind.request_headers = headers;
invoke->u.S_MethodInvoke_Ind.request_body =
octstr_duplicate(pdu->u.Post.data);
invoke->u.S_MethodInvoke_Ind.session_headers =
http_header_duplicate(sm->http_headers);
invoke->u.S_MethodInvoke_Ind.addr_tuple =
wap_addr_tuple_duplicate(sm->addr_tuple);
invoke->u.S_MethodInvoke_Ind.client_SDU_size =
sm->client_SDU_size;
invoke->u.S_MethodInvoke_Ind.session_id =
msm->session_id;
msm->invoke = invoke;
},
HOLDING)
ROW(HOLDING,
Release_Event,
1,
{
/* S-MethodInvoke.ind */
dispatch_to_appl(msm->invoke);
msm->invoke = NULL;
},
REQUESTING)
ROW(HOLDING,
Abort_Event,
1,
{
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
/* Tr-Abort.req(abort reason) the method */
method_abort(msm, e->reason);
},
NULL_METHOD)
ROW(HOLDING,
TR_Abort_Ind,
e->abort_code == WSP_ABORT_DISCONNECT,
{
WAPEvent *wsp_event;
/* Disconnect the session */
wsp_event = wap_event_create(Disconnect_Event);
wsp_event->u.Disconnect_Event.session_handle = msm->session_id;
/* We put this on the queue instead of doing it right away,
* because the session machine is currently our caller and
* we don't want to recurse. We put it in the front of
* the queue because the state machine definitions expect
* an event to be handled completely before the next is
* started. */
gwlist_insert(queue, 0, wsp_event);
},
HOLDING)
ROW(HOLDING,
TR_Abort_Ind,
e->abort_code == WSP_ABORT_SUSPEND,
{
WAPEvent *wsp_event;
/* Suspend the session */
wsp_event = wap_event_create(Suspend_Event);
wsp_event->u.Suspend_Event.session_handle = msm->session_id;
/* See story for Disconnect, above */
gwlist_insert(queue, 0, wsp_event);
},
HOLDING)
ROW(HOLDING,
TR_Abort_Ind,
e->abort_code != WSP_ABORT_DISCONNECT
&& e->abort_code != WSP_ABORT_SUSPEND,
{
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
},
NULL_METHOD)
ROW(REQUESTING,
S_MethodInvoke_Res,
1,
{
WAPEvent *wtp_event;
/* Send TR-Invoke.res to WTP */
wtp_event = wap_event_create(TR_Invoke_Res);
wtp_event->u.TR_Invoke_Res.handle = msm->transaction_id;
dispatch_to_wtp_resp(wtp_event);
},
PROCESSING)
/* MISSING: REQUESTING, S-MethodAbort.req */
ROW(REQUESTING,
Abort_Event,
1,
{
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
/* TR-Abort.req(abort reason) the method */
method_abort(msm, e->reason);
/* S-MethodAbort.ind(abort reason) */
indicate_method_abort(msm, e->reason);
},
NULL_METHOD)
ROW(REQUESTING,
TR_Abort_Ind,
e->abort_code == WSP_ABORT_DISCONNECT,
{
WAPEvent *wsp_event;
/* Disconnect the session */
wsp_event = wap_event_create(Disconnect_Event);
wsp_event->u.Disconnect_Event.session_handle = msm->session_id;
gwlist_insert(queue, 0, wsp_event);
},
REQUESTING)
ROW(REQUESTING,
TR_Abort_Ind,
e->abort_code == WSP_ABORT_SUSPEND,
{
WAPEvent *wsp_event;
/* Suspend the session */
wsp_event = wap_event_create(Suspend_Event);
wsp_event->u.Suspend_Event.session_handle = msm->session_id;
gwlist_insert(queue, 0, wsp_event);
},
REQUESTING)
ROW(REQUESTING,
TR_Abort_Ind,
e->abort_code != WSP_ABORT_DISCONNECT
&& e->abort_code != WSP_ABORT_SUSPEND,
{
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
/* S-MethodAbort.ind(abort reason) */
indicate_method_abort(msm, e->abort_code);
},
NULL_METHOD)
ROW(PROCESSING,
S_MethodResult_Req,
1,
{
WAPEvent *wtp_event;
WSP_PDU *new_pdu;
/* TR-Result.req */
new_pdu = wsp_pdu_create(Reply);
new_pdu->u.Reply.status =
wsp_convert_http_status_to_wsp_status(e->status);
new_pdu->u.Reply.headers =
wsp_headers_pack(e->response_headers, 1, sm->encoding_version);
new_pdu->u.Reply.data = octstr_duplicate(e->response_body);
/* Send TR-Result.req to WTP */
wtp_event = wap_event_create(TR_Result_Req);
wtp_event->u.TR_Result_Req.user_data = wsp_pdu_pack(new_pdu);
wtp_event->u.TR_Result_Req.handle = msm->transaction_id;
dispatch_to_wtp_resp(wtp_event);
wsp_pdu_destroy(new_pdu);
},
REPLYING)
/* MISSING: PROCESSING, S-MethodAbort.req */
ROW(PROCESSING,
Abort_Event,
1,
{
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
/* TR-Abort.req(abort reason) the method */
method_abort(msm, e->reason);
/* S-MethodAbort.ind(abort reason) */
indicate_method_abort(msm, e->reason);
},
NULL_METHOD)
ROW(PROCESSING,
TR_Abort_Ind,
e->abort_code == WSP_ABORT_DISCONNECT,
{
WAPEvent *wsp_event;
/* Disconnect the session */
wsp_event = wap_event_create(Disconnect_Event);
wsp_event->u.Disconnect_Event.session_handle = msm->session_id;
gwlist_insert(queue, 0, wsp_event);
},
PROCESSING)
ROW(PROCESSING,
TR_Abort_Ind,
e->abort_code == WSP_ABORT_SUSPEND,
{
WAPEvent *wsp_event;
/* Suspend the session */
wsp_event = wap_event_create(Suspend_Event);
wsp_event->u.Suspend_Event.session_handle = msm->session_id;
gwlist_insert(queue, 0, wsp_event);
},
PROCESSING)
ROW(PROCESSING,
TR_Abort_Ind,
e->abort_code != WSP_ABORT_DISCONNECT
&& e->abort_code != WSP_ABORT_SUSPEND,
{
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
/* S-MethodAbort.ind(abort reason) */
indicate_method_abort(msm, e->abort_code);
},
NULL_METHOD)
/* MISSING: REPLYING, S-MethodAbort.req */
ROW(REPLYING,
Abort_Event,
1,
{
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
/* TR-Abort.req(abort reason) the method */
method_abort(msm, e->reason);
/* S-MethodAbort.ind(abort reason) */
indicate_method_abort(msm, e->reason);
},
NULL_METHOD)
ROW(REPLYING,
TR_Result_Cnf,
1,
{
WAPEvent *new_event;
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
/* S-MethodResult.cnf */
/* we don't do acknowledgement headers */
new_event = wap_event_create(S_MethodResult_Cnf);
new_event->u.S_MethodResult_Cnf.server_transaction_id =
msm->transaction_id;
new_event->u.S_MethodResult_Cnf.session_id = msm->session_id;
dispatch_to_appl(new_event);
},
NULL_METHOD)
ROW(REPLYING,
TR_Abort_Ind,
e->abort_code == WSP_ABORT_DISCONNECT,
{
WAPEvent *wsp_event;
/* Disconnect the session */
wsp_event = wap_event_create(Disconnect_Event);
wsp_event->u.Disconnect_Event.session_handle = msm->session_id;
gwlist_insert(queue, 0, wsp_event);
},
REPLYING)
ROW(REPLYING,
TR_Abort_Ind,
e->abort_code == WSP_ABORT_SUSPEND,
{
WAPEvent *wsp_event;
/* Suspend the session */
wsp_event = wap_event_create(Suspend_Event);
wsp_event->u.Suspend_Event.session_handle = msm->session_id;
gwlist_insert(queue, 0, wsp_event);
},
REPLYING)
ROW(REPLYING,
TR_Abort_Ind,
e->abort_code != WSP_ABORT_DISCONNECT
&& e->abort_code != WSP_ABORT_SUSPEND,
{
/* Decrement N_Methods */
/* we don't keep track of N_Methods because it's unlimited */
/* S-MethodAbort.ind(abort reason) */
indicate_method_abort(msm, e->abort_code);
},
NULL_METHOD)
#undef ROW
#undef STATE_NAME
gateway-1.4.3/wap/wap_addr.c 0000644 0001750 0001750 00000011121 11132672003 014721 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wap_addr.c - implement WAPAddr and WAPAddrTuple types.
*/
#include
#include
#include "gwlib/gwlib.h"
#include "wap_addr.h"
WAPAddr *wap_addr_create(Octstr *address, long port)
{
WAPAddr *addr;
addr = gw_malloc(sizeof(*addr));
addr->address = octstr_duplicate(address);
addr->iaddr = inet_addr(octstr_get_cstr(address));
addr->port = port;
return addr;
}
void wap_addr_destroy(WAPAddr *addr)
{
if (addr != NULL) {
octstr_destroy(addr->address);
gw_free(addr);
}
}
int wap_addr_same(WAPAddr *a, WAPAddr *b)
{
/* XXX which ordering gives the best heuristical performance? */
return a->port == b->port && a->iaddr == b->iaddr;
}
WAPAddrTuple *wap_addr_tuple_create(Octstr *rmt_addr, long rmt_port,
Octstr *lcl_addr, long lcl_port)
{
WAPAddrTuple *tuple;
tuple = gw_malloc(sizeof(*tuple));
tuple->remote = wap_addr_create(rmt_addr, rmt_port);
tuple->local = wap_addr_create(lcl_addr, lcl_port);
return tuple;
}
void wap_addr_tuple_destroy(WAPAddrTuple *tuple)
{
if (tuple != NULL) {
wap_addr_destroy(tuple->remote);
wap_addr_destroy(tuple->local);
gw_free(tuple);
}
}
int wap_addr_tuple_same(WAPAddrTuple *a, WAPAddrTuple *b)
{
return wap_addr_same(a->remote, b->remote) &&
wap_addr_same(a->local, b->local);
}
WAPAddrTuple *wap_addr_tuple_duplicate(WAPAddrTuple *tuple)
{
if (tuple == NULL)
return NULL;
return wap_addr_tuple_create(tuple->remote->address,
tuple->remote->port,
tuple->local->address,
tuple->local->port);
}
void wap_addr_tuple_dump(WAPAddrTuple *tuple)
{
debug("wap", 0, "WAPAddrTuple %p = <%s:%ld> - <%s:%ld>",
(void *) tuple,
octstr_get_cstr(tuple->remote->address),
tuple->remote->port,
octstr_get_cstr(tuple->local->address),
tuple->local->port);
}
gateway-1.4.3/wap/.cvsignore 0000640 0001750 0001750 00000000004 10750451707 015001 0 ustar soren soren *.i
gateway-1.4.3/wap/wtls_pdu.h 0000644 0001750 0001750 00000023673 11132672003 015025 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wtls_pdu.h - definitions for unpacked WTLS protocol data units
*
*/
#ifndef PDU_H
#define PDU_H
#include "gwlib/list.h"
#include "gwlib/octstr.h"
#include "wtls.h"
typedef enum wtls_pdu_modes {
ChangeCipher_PDU = 1,
Alert_PDU,
Handshake_PDU,
Application_PDU
} wtls_pdu_modes;
typedef enum handshake_type{
hello_request = 0,
client_hello = 1,
server_hello = 2,
certificate = 11,
server_key_exchange = 12,
certificate_request = 13,
server_hello_done = 14,
certificate_verify = 15,
client_key_exchange = 16,
finished = 20
} HandshakeType;
typedef enum compmethod {
null_comp = 0
} CompressionMethod;
typedef enum certificateformat {
WTLSCert = 1,
X509Cert,
X968Cert
} CertificateFormat;
typedef enum sig_algo {
anonymous,
ecdsa_sha,
rsa_sha,
} SignatureAlgorithm;
/*typedef enum keyex_algo {
rsa,
rsa_anon,
dh_anon,
ecdh_anon,
ecdh_ecdsa,
} KeyExchangeAlgorithm;*/
typedef enum keyex_suite {
null_k,
shared_secret,
dh_anon,
dh_anon_512,
dh_anon_768,
rsa_anon,
rsa_anon_512,
rsa_anon_768,
rsa,
rsa_512,
rsa_768,
ecdh_anon,
ecdh_anon_113,
ecdh_anon_131,
ecdh_ecdsa,
} KeyExchangeSuite;
typedef enum pubkey_algo {
rsa_pubkey,
diffie_hellman_pubkey,
elliptic_curve_pubkey,
} PublicKeyAlgorithm;
typedef enum identifier_type {
null = 0,
text,
binary,
key_hash_sha = 254,
x509_name = 255
} IdentifierType;
typedef enum public_key_type {
rsa_key = 2,
ecdh_key = 3,
ecdsa_key = 4
} PublicKeyType;
typedef enum ecbasistype {
ec_basis_onb = 1,
ec_basis_trinomial,
ec_basis_pentanomial,
ec_basis_polynomial
} ECBasisType;
typedef enum ecfield {
ec_prime_p,
ec_characteristic_two
} ECField;
typedef struct random {
long gmt_unix_time;
Octstr *random_bytes;
} Random;
typedef struct ecpoint {
Octstr *point;
} ECPoint;
typedef ECPoint ECPublicKey;
typedef struct dhpublickey {
Octstr *dh_Y;
} DHPublicKey;
typedef struct rsa_public_key {
Octstr *rsa_exponent;
Octstr *rsa_modulus;
} RSAPublicKey;
typedef struct public_key {
/* ecdh */
ECPublicKey *ecdh_pubkey;
/* ecdsa */
ECPublicKey *ecdsa_pubkey;
/* rsa */
RSAPublicKey *rsa_pubkey;
} PublicKey;
typedef struct identifier {
IdentifierType id_type;
/* text */
int charset;
Octstr *name;
/* binary */
Octstr *identifier;
/* key_hash_sha */
Octstr *key_hash;
/* x509 */
Octstr *distinguished_name;
} Identifier;
typedef struct eccurve {
Octstr *a;
Octstr *b;
Octstr *seed;
} ECCurve;
typedef struct dh_parameters{
int dh_e;
Octstr *dh_p;
Octstr *dh_g;
} DHParameters;
typedef struct ec_parameters{
ECField field;
/* case ec_prime_p */
Octstr *prime_p;
/* case ec_characteristic_two */
int m;
ECBasisType basis;
/* case ec_basis_onb : nothing*/
/* case ec_trinomial */
int k;
/* case ec_pentanomial */
int k1;
int k2;
int k3;
/* case ec_basis_polynomial */
Octstr *irreducible;
ECCurve *curve;
ECPoint *base;
Octstr *order;
Octstr *cofactor;
} ECParameters;
typedef struct parameter_set {
long length;
/* rsa: empty */
/* diffie-hellman */
DHParameters *dhparams;
/* eliptic curve */
ECParameters *ecparams;
} ParameterSet;
typedef struct parameter_specifier {
int param_index;
ParameterSet *param_set;
} ParameterSpecifier;
typedef struct key_exchange_id {
int key_exchange_suite;
ParameterSpecifier *param_specif;
Identifier *identifier;
} KeyExchangeId;
typedef struct signature {
/* case anonymous */
/* nothing */
/* case ecdsa_sha and rsa_sha */
List *sha_hash;
} Signature;
typedef struct to_be_signed_cert {
int certificate_version;
SignatureAlgorithm signature_algo;
Identifier *issuer;
long valid_not_before;
long valid_not_after;
Identifier *subject;
PublicKeyType pubkey_type;
ParameterSpecifier *param_spec;
PublicKey *pubkey;
} ToBeSignedCertificate;
typedef struct wtls_cert {
ToBeSignedCertificate *tobesigned_cert;
Signature *signature;
} WTLSCertificate;
typedef struct rsa_secret{
int client_version;
List *random;
} RSASecret;
typedef struct rsa_encrypted_secret {
Octstr *encrypted_secret;
} RSAEncryptedSecret;
typedef struct cipher_suite {
int bulk_cipher_algo;
int mac_algo;
} CipherSuite;
typedef struct cert_request {
List *trusted_authorities; // List of KeyExchangeIds
} CertificateRequest;
typedef struct cert_verify {
Signature *signature;
} CertificateVerify;
typedef struct hello_request
{
int dummy; /* nothing here */
} HelloRequest;
typedef struct client_hello
{
int clientversion;
Random *random;
Octstr *session_id;
List *client_key_ids;
List *trusted_key_ids;
List *ciphersuites; // list of CipherSuites
List *comp_methods;
int snmode;
int krefresh;
} ClientHello;
typedef struct server_hello
{
int serverversion;
Random *random;
Octstr *session_id;
int client_key_id;
CipherSuite *ciphersuite;
CompressionMethod comp_method;
int snmode;
int krefresh;
} ServerHello;
typedef struct certificate {
CertificateFormat certificateformat;
/* case WTLS */
WTLSCertificate *wtls_certificate;
/* case X509 */
Octstr *x509_certificate;
/* X968 */
Octstr *x968_certificate;
} Certificate;
typedef struct server_key_exchange
{
ParameterSpecifier *param_spec;
/* case rsa_anon */
RSAPublicKey *rsa_params;
/* case dh_anon */
DHPublicKey *dh_params;
/* case ecdh_anon */
ECPublicKey *ecdh_params;
} ServerKeyExchange;
typedef struct client_key_exchange
{
/* case rsa and rsa_anon*/
RSAEncryptedSecret *rsa_params;
/* case dh_anon */
DHPublicKey *dh_anon_params;
/* case ecdh_anon and ecdh_ecdsa*/
ECPublicKey *ecdh_params;
} ClientKeyExchange;
typedef struct finished {
Octstr *verify_data;
} Finished;
typedef struct server_hello_done
{
int dummy; /* nothing here */
} ServerHelloDone;
typedef struct cc
{
int change;
} ChangeCipher;
typedef struct alert
{
int level;
int desc;
Octstr *chksum;
} Alert;
typedef struct handshake
{
HandshakeType msg_type;
int length;
/* case hello_request */
/* case client_hello */
ClientHello *client_hello;
/* case server_hello */
ServerHello *server_hello;
/* case certificate */
Certificate *certificate;
/* case server_key_exchange */
ServerKeyExchange *server_key_exchange;
/* case certificate_request */
CertificateRequest *certificate_request;
/* case server_hello_done */
ServerHelloDone *server_hello_done;
/* case certificate_verify */
CertificateVerify *cert_verify;
/* case client_key_exchange */
ClientKeyExchange *client_key_exchange;
/* case finished */
Finished *finished;
} Handshake;
typedef struct application
{
Octstr *data;
} Application;
typedef struct wtls_pdu {
int type;
int reserved;
int cipher;
int seqnum;
int rlen;
union {
ChangeCipher cc;
Alert alert;
Handshake handshake;
Application application;
} u;
} wtls_PDU;
typedef struct wtls_payload {
int type;
int reserved;
int cipher;
int seqnum;
int rlen;
Octstr *data;
} wtls_Payload;
/* Prototypes */
wtls_PDU *wtls_pdu_create(int type);
void wtls_pdu_destroy(wtls_PDU *msg);
void wtls_pdu_dump(wtls_PDU *msg, int level);
wtls_PDU *wtls_pdu_unpack(wtls_Payload *payload, WTLSMachine* wtls_machine);
wtls_Payload *wtls_pdu_pack(wtls_PDU *pdu, WTLSMachine* wtls_machine);
wtls_Payload *wtls_payload_unpack(Octstr *data);
Octstr *wtls_payload_pack(wtls_Payload *payload);
void wtls_payload_destroy(wtls_Payload *payload);
List* wtls_unpack_payloadlist (Octstr *data);
Octstr* wtls_pack_payloadlist (List* payloadlist);
#endif
gateway-1.4.3/wap/wtls_statesupport.h 0000644 0001750 0001750 00000017600 11132672002 017002 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/* wtls_statesupport.h
*
*/
#ifndef WTLS_STATESUPPORT_H
#define WTLS_STATESUPPORT_H
#include "gwlib/gwlib.h"
#include "wtls_pdu.h"
#include "wtls.h"
#define KEYSIZE_MAX 2048
#define NOT_EXPORTABLE 0
#define EXPORTABLE 1
#define BLOCK 0
#define STREAM 1
/* These enums and tables are pulled straight from the WTLS appendicies.
Go and have a look at them if these aren't particularly clear. Obviously, since NULL
is a builtin, and since RSA/MD5/SHA are all macros referenced by the openssl
libraries, the names have had to be slightly altered to protect the innocent :->
*/
enum key_exchange_suites{
NULL_keyxchg,
SHARED_SECRET,
DH_anon,
DH_anon_512,
RSA_anon,
RSA_anon_512,
RSA_anon_768,
RSA_NOLIMIT,
RSA_512,
RSA_768,
ECDH_anon,
ECDH_anon_113,
ECDH_anon_131,
ECDH_ECDSA_NOLIMIT
};
enum bulk_algorithms {
NULL_bulk,
RC5_CBC_40,
RC5_CBC_56,
RC5_CBC,
DES_CBC_40,
DES_CBC,
TRIPLE_DES_CBC_EDE,
IDEA_CBC_40,
IDEA_CBC_56,
IDEA_CBC
};
enum keyed_macs{
SHA_0,
SHA_40,
SHA_80,
SHA_NOLIMIT,
SHA_XOR_40,
MD5_40,
MD5_80,
MD5_NOLIMIT
};
typedef struct
{
const char* title;
int key_size_limit;
} keyxchg_table_t;
static keyxchg_table_t keyxchg_table[] = {
{"NULL",0},
{"Shared Secret", KEYSIZE_MAX},
{"DH-anon",KEYSIZE_MAX},
{"DH-anon-512",512},
{"DH-anon-768",768},
{"RSA-anon", KEYSIZE_MAX},
{"RSA-anon-512",512},
{"RSA-anon-768",768},
{"RSA",KEYSIZE_MAX},
{"RSA-512", 512},
{"RSA-768",768},
{"ECDH-anon",KEYSIZE_MAX},
{"ECDH-anon-113",113},
{"ECDH-anon-131",131},
{"ECDH-ECDSA",KEYSIZE_MAX}
};
typedef struct
{
const char* title;
int is_exportable;
int block_or_stream;
int key_material;
int expanded_key_material;
int effective_key_bits;
int iv_size;
int block_size;
} bulk_table_t;
static bulk_table_t bulk_table[] = {
{"NULL Encryption",EXPORTABLE,STREAM,0,0,0,0,0},
{"RC5-CBC-40",EXPORTABLE,BLOCK,5,16,40,8,8},
{"RC5-CBC-56",EXPORTABLE,BLOCK,7,16,56,8,8},
{"RC5-CBC",NOT_EXPORTABLE,BLOCK,16,16,128,8,8},
{"DES-CBC-40",EXPORTABLE,BLOCK,5,8,40,8,8},
{"DES-CBC",NOT_EXPORTABLE,BLOCK,8,8,56,8,8},
{"3DES-CBC-EDE",NOT_EXPORTABLE,BLOCK,24,24,168,8,8},
{"IDEA-CBC-40",EXPORTABLE,BLOCK,5,16,40,8,8},
{"IDEA-CBC-56",EXPORTABLE,BLOCK,7,16,56,8,8},
{"IDEA-CBC",NOT_EXPORTABLE,BLOCK,16,16,128,8,8}
};
typedef struct
{
const char* title;
int key_size;
int mac_size;
} hash_table_t;
static hash_table_t hash_table[] = {
{"SHA-0",0,0},
{"SHA1-40",20,5},
{"SHA1-80",20,10},
{"SHA1",20,20},
{"SHA-XOR-40",0,5},
{"MD5-40",16,5},
{"MD5-80",16,10},
{"MD5",16,16}
};
Octstr* wtls_calculate_prf(Octstr* secret, Octstr* label,
Octstr* seed, int byteLength, WTLSMachine* wtls_machine);
RSAPublicKey* wtls_get_rsapublickey(void);
Random* wtls_get_random(void);
Octstr* wtls_decrypt(Octstr* buffer, WTLSMachine* wtls_machine);
Octstr* wtls_encrypt(Octstr* buffer, WTLSMachine* wtls_machine, int recordType);
Octstr* wtls_decrypt_rsa(Octstr* encryptedData);
/* The wtls_choose* functions implement the decision making process behind the
protocol negotiations in wtls. */
CipherSuite* wtls_choose_ciphersuite(List* ciphersuites);
int wtls_choose_clientkeyid(List* clientKeyIDs);
int wtls_choose_snmode(int snmode);
int wtls_choose_krefresh(int krefresh);
/* The *_are_identical functions all return 1 if the packets match the condition as
* expressed in the function name. As each packet can contain a "list" of pdus, we
* need to search that list and return whether or not they contain identical pdus as listed.
* On failure, they will return non-zero
*/
int clienthellos_are_identical (List* pdu_list, List* last_received_packet);
int certifcateverifys_are_identical (List* pdu_list, List* last_received_packet);
int certificates_are_identical (List* pdu_list, List* last_received_packet);
int clientkeyexchanges_are_identical (List* pdu_list, List* last_received_packet);
int changecipherspecs_are_identical (List* pdu_list, List* last_received_packet);
int finisheds_are_indentical (List* pdu_list, List* last_received_packet);
/* the packet_contains_* functions all return 1 if the packet contains a pdu of the type
* expressed in the function name.
*/
int packet_contains_changecipherspec (List* pdu_list);
int packet_contains_finished (List* pdu_list);
int packet_contains_optional_stuff (List* pdu_list);
int packet_contains_userdata (List* pdu_list);
int packet_contains_clienthello (List* pdu_list);
/* the is_*_alert functions return 1 if the packet is a pdu of the type expressed in the
* function name.
*/
int is_critical_alert (List* pdu_list);
int is_warning_alert (List* pdu_list);
void calculate_client_key_block(WTLSMachine *wtls_machine);
void calculate_server_key_block(WTLSMachine *wtls_machine);
#endif
gateway-1.4.3/wap/wap_events.c 0000644 0001750 0001750 00000017340 11132672002 015323 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wap_events.c - functions for manipulating wapbox events
*
* Aarno Syvnen
* Lars Wirzenius
*/
#include "gwlib/gwlib.h"
#include "wsp_caps.h"
#include "wap_events.h"
#include "wtls_pdu.h"
WAPEvent *wap_event_create_real(WAPEventName type, const char *file, long line,
const char *func) {
WAPEvent *event;
gw_assert(type >= 0);
gw_assert(type < WAPEventNameCount);
event = gw_malloc_trace(sizeof(WAPEvent), file, line, func);
event->type = type;
switch (event->type) {
#define WAPEVENT(name, prettyname, fields) \
case name: \
{ struct name *p = &event->u.name; fields } \
break;
#define OCTSTR(name) p->name = NULL;
#define OPTIONAL_OCTSTR(name) p->name = NULL;
#define INTEGER(name) p->name = 0;
#define WTLSPDUS(name) p->name = NULL;
#define HTTPHEADER(name) p->name = NULL;
#define ADDRTUPLE(name) p->name = NULL;
#define CAPABILITIES(name) p->name = NULL;
#include "wap_events.def"
default:
panic(0, "Unknown WAP event type %d", event->type);
}
return event;
}
void wap_event_destroy(WAPEvent *event) {
if (event == NULL)
return;
wap_event_assert(event);
switch (event->type) {
#define WAPEVENT(name, prettyname, fields) \
case name: \
{ struct name *p = &event->u.name; fields; } \
break;
#define OCTSTR(name) octstr_destroy(p->name);
#define OPTIONAL_OCTSTR(name) octstr_destroy(p->name);
#define INTEGER(name) p->name = 0;
#define WTLSPDUS(name) debug("wap.events",0,"You need to create wtls_pdulist_destroy!");
#define HTTPHEADER(name) http_destroy_headers(p->name);
#define ADDRTUPLE(name) wap_addr_tuple_destroy(p->name);
#define CAPABILITIES(name) wsp_cap_destroy_list(p->name);
#include "wap_events.def"
default:
panic(0, "Unknown WAPEvent type %d", (int) event->type);
}
gw_free(event);
}
void wap_event_destroy_item(void *event) {
wap_event_destroy(event);
}
WAPEvent *wap_event_duplicate(WAPEvent *event) {
WAPEvent *new;
if (event == NULL)
return NULL;
wap_event_assert(event);
new = gw_malloc(sizeof(WAPEvent));
new->type = event->type;
switch (event->type) {
#define WAPEVENT(name, prettyname, fields) \
case name: \
{ struct name *p = &new->u.name; \
struct name *q = &event->u.name; \
fields } \
break;
#define OCTSTR(name) p->name = octstr_duplicate(q->name);
#define OPTIONAL_OCTSTR(name) p->name = octstr_duplicate(q->name);
#define INTEGER(name) p->name = q->name;
#define WTLSPDUS(name) debug("wap.events",0,"You need to implement wtls_pdulist_duplicate!");
#define HTTPHEADER(name) p->name = http_header_duplicate(q->name);
#define ADDRTUPLE(name) p->name = wap_addr_tuple_duplicate(q->name);
#define CAPABILITIES(name) p->name = wsp_cap_duplicate_list(q->name);
#include "wap_events.def"
default:
panic(0, "Unknown WAP event type %d", event->type);
}
return new;
}
const char *wap_event_name(WAPEventName type) {
switch (type) {
#define WAPEVENT(name, prettyname, fields) \
case name: return prettyname;
#include "wap_events.def"
default:
panic(0, "Unknown WAPEvent type %d", (int) type);
return "unknown WAPEventName";
}
}
void wap_event_dump(WAPEvent *event) {
debug("wap.event", 0, "Dumping WAPEvent %p", (void *) event);
if (event != NULL) {
debug("wap.event", 0, " type = %s",
wap_event_name(event->type));
switch (event->type) {
#define WAPEVENT(name, prettyname, fields) \
case name: \
{ struct name *p = &event->u.name; fields; break; }
#define OCTSTR(name) \
debug("wap.event", 0, "%s =", #name); \
octstr_dump(p->name, 1);
#define OPTIONAL_OCTSTR(name) \
if (p->name == NULL) \
debug("wap.event", 0, "%s = NULL", #name); \
else { \
debug("wap.event", 0, "%s =", #name); \
octstr_dump(p->name, 1); \
}
#define INTEGER(name) \
debug("wap.event", 0, " %s = %ld", #name, p->name);
#define WTLSPDUS(name) \
debug("wap.event",0,"You need to implement wtls_payloadlist_dump!");
#define HTTPHEADER(name) \
if (p->name == NULL) \
debug("wap.event", 0, "%s = NULL", #name); \
else \
http_header_dump(p->name);
#define ADDRTUPLE(name) wap_addr_tuple_dump(p->name);
#define CAPABILITIES(name) wsp_cap_dump_list(p->name);
#include "wap_events.def"
default:
debug("wap.event", 0, "Unknown type");
}
}
debug("wap.event", 0, "WAPEvent dump ends.");
}
void wap_event_assert(WAPEvent *event) {
gw_assert(event != NULL),
gw_assert(event->type >= 0);
gw_assert(event->type < WAPEventNameCount);
switch (event->type) {
#define WAPEVENT(name, prettyname, fields) \
case name: \
{ struct name *p = &event->u.name; fields; p = NULL; break; }
#define OCTSTR(name) \
gw_assert(p->name != NULL); \
/* This is a trick to make the Octstr module run its assertions */ \
gw_assert(octstr_len(p->name) >= 0);
#define OPTIONAL_OCTSTR(name) \
gw_assert(p->name == NULL || octstr_len(p->name) >= 0);
#define INTEGER(name)
#define WTLSPDUS(name)
#define HTTPHEADER(name)
#define ADDRTUPLE(name) \
gw_assert(p->name != NULL);
#define CAPABILITIES(name)
#include "wap_events.def"
default:
debug("wap.event", 0, "Unknown type");
}
}
gateway-1.4.3/wap/wtp_tid.c 0000644 0001750 0001750 00000021377 11132672003 014630 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wtp_tid.c - Implementation of WTP tid validation tests. Note that only
* WTP responder uses tid validation.
*
* By Aarno Syvnen for Wapit Ltd.
*/
#include "gwlib/gwlib.h"
#include "wtp_tid.h"
/*
* Constants used for defining the tid cache status
*/
enum {
no_cache = -1,
iniatilised = -2,
not_iniatilised = -3,
cached = 0
};
/*
* Global data structure:
*
* Tid cache is implemented by using a library object List
*/
static List *tid_cache = NULL;
/*****************************************************************************
* Prototypes of internal functions
*/
static WTPCached_tid *cache_item_create_empty(void);
static void cache_item_destroy(void *item);
/*
static void cache_item_dump(WTPCached_tid *item);
*/
static void add_tid(WTPRespMachine *resp_machine, long tid);
static void set_tid_by_item(WTPCached_tid *item, long tid);
static int tid_in_window(long rcv_tid, long last_tid);
static WTPCached_tid *tid_cached(WTPRespMachine *resp_machine);
/******************************************************************************
*
* External functions:
*/
void wtp_tid_cache_init(void)
{
tid_cache = gwlist_create();
}
void wtp_tid_cache_shutdown(void)
{
debug("wap.wtp_tid", 0, "%ld items left in the tid cache",
gwlist_len(tid_cache));
gwlist_destroy(tid_cache, cache_item_destroy);
}
/*
* Tid verification is invoked, when tid_new flag of the incoming message is
* on. It is not, if the initiator is not yet cached. If initiator is cached,
* the received tid is stored.
*/
int wtp_tid_is_valid(WAPEvent *event, WTPRespMachine *resp_machine)
{
long rcv_tid = -1,
last_tid = -1;
WTPCached_tid *item = NULL;
#if 0
debug("wap.wtp.tid", 0, "starting validation");
#endif
rcv_tid = resp_machine->tid;
if (!event->u.RcvInvoke.tid_new) {
/*
* First we check whether the current initiator has a cache item for it.
*/
if ((item = tid_cached(resp_machine)) == NULL) {
if (event->u.RcvInvoke.no_cache_supported)
return no_cached_tid;
else {
#if 0
debug("wap.wtp.tid", 0, "empty cache");
#endif
add_tid(resp_machine, rcv_tid);
return ok;
}
}
/*
* If it has, we check if the message is a duplicate or has tid wrapped up
* confusingly.
*/
last_tid = item->tid;
if (tid_in_window(rcv_tid, last_tid) == 0){
info(0, "WTP_TID: tid out of the window");
return fail;
} else {
#if 0
debug("wap.wtp.tid", 0, "tid in the window");
#endif
set_tid_by_item(item, rcv_tid);
return ok;
}
} else {
info(0, "WTP_TID: tid_new flag on");
rcv_tid = 0;
if (item == NULL) {
add_tid(resp_machine, rcv_tid);
} else {
set_tid_by_item(item, rcv_tid);
}
return fail;
}
/*
* This return is unnecessary but the compiler demands it
*/
return fail;
}
/*
* Changes tid value used by an existing initiator. Input responder machine
* and the new tid.
*/
void wtp_tid_set_by_machine(WTPRespMachine *resp_machine, long tid)
{
WTPCached_tid *item = NULL;
item = tid_cached(resp_machine);
set_tid_by_item(item, tid);
}
/*****************************************************************************
*
* Internal functions:
*
* Checks whether the received tid is inside the window of acceptable ones.
* The size of the window is set by the constant WTP_TID_WINDOW_SIZE (half of
* the tid space is the recommended value).
*
* Inputs: stored tid, received tid. Output 0, if received tid is outside the
* window, 1, if it is inside.
*/
static int tid_in_window(long rcv_tid, long last_tid)
{
#if 0
debug("wap.wtp.tid", 0, "tids were rcv_tid, %ld and last_tid, %ld"
" and test window %ld", rcv_tid, last_tid, WTP_TID_WINDOW_SIZE);
#endif
if (last_tid == rcv_tid) {
return 0;
}
if (rcv_tid > last_tid) {
if (abs(rcv_tid - last_tid) <= WTP_TID_WINDOW_SIZE) {
return 1;
} else {
return 0;
}
}
if (rcv_tid < last_tid) {
if (abs(rcv_tid - last_tid) >= WTP_TID_WINDOW_SIZE){
return 1;
} else {
return 0;
}
}
/*
* Following return is unnecessary but our compiler demands it
*/
return 0;
}
static WTPCached_tid *cache_item_create_empty(void)
{
WTPCached_tid *item = NULL;
item = gw_malloc(sizeof(*item));
item->addr_tuple = NULL;
item->tid = 0;
return item;
}
static void cache_item_destroy(void *p)
{
WTPCached_tid *item;
item = p;
wap_addr_tuple_destroy(item->addr_tuple);
gw_free(item);
}
/*
* Checking whether there is an item stored for a specific initiator. Receives
* address quadruplet - the identifier it uses - from object WTPRespMachine.
* Ditto tid. Returns the item or NULL, if there is not one. Initiator is
* identified by the address four-tuple.
*/
static int tid_is_cached(void *a, void *b)
{
WAPAddrTuple *initiator_profile;
WTPCached_tid *item;
item = a;
initiator_profile = b;
return wap_addr_tuple_same(item->addr_tuple, initiator_profile);
}
static WTPCached_tid *tid_cached(WTPRespMachine *resp_machine)
{
WTPCached_tid *item = NULL;
item = gwlist_search(tid_cache, resp_machine->addr_tuple, tid_is_cached);
return item;
}
/*
* Adds an item to the tid cache, one item per every initiator. Initiator is
* identified by the address four-tuple, fetched from a wtp responder machine.
*/
static void add_tid(WTPRespMachine *resp_machine, long tid)
{
WTPCached_tid *new_item = NULL;
new_item = cache_item_create_empty();
new_item->addr_tuple = wap_addr_tuple_duplicate(resp_machine->addr_tuple);
new_item->tid = tid;
gwlist_append(tid_cache, new_item);
}
/*
* Set tid for an existing initiator. Input a cache item and the new tid.
*/
static void set_tid_by_item(WTPCached_tid *item, long tid)
{
gwlist_lock(tid_cache);
item->tid = tid;
gwlist_unlock(tid_cache);
}
gateway-1.4.3/wap/wsp_push_client_machine.def 0000644 0001750 0001750 00000006345 11132672003 020362 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* wsp-push-client-machine.h: Define wsp push client state machine
*
* By Aarno Syvnen for Wapit Ltd.
*/
#if !defined(INTEGER)
#error "Macro INTEGER not defined."
#elif !defined(HTTPHEADERS)
#error "Macro HTTPHEADERS not defined."
#elif !defined(MACHINE)
#error "Macro MACHINE is not defined."
#endif
MACHINE(
INTEGER(state)
INTEGER(client_push_id)
INTEGER(transaction_id)
INTEGER(session_id)
HTTPHEADERS(push_headers)
)
#undef INTEGER
#undef HTTPHEADERS
#undef MACHINE
gateway-1.4.3/configure.in 0000644 0001750 0001750 00000112164 11132672005 014531 0 ustar soren soren dnl /* ====================================================================
dnl * The Kannel Software License, Version 1.0
dnl *
dnl * Copyright (c) 2001-2009 Kannel Group
dnl * Copyright (c) 1998-2001 WapIT Ltd.
dnl * All rights reserved.
dnl *
dnl * Redistribution and use in source and binary forms, with or without
dnl * modification, are permitted provided that the following conditions
dnl * are met:
dnl *
dnl * 1. Redistributions of source code must retain the above copyright
dnl * notice, this list of conditions and the following disclaimer.
dnl *
dnl * 2. Redistributions in binary form must reproduce the above copyright
dnl * notice, this list of conditions and the following disclaimer in
dnl * the documentation and/or other materials provided with the
dnl * distribution.
dnl *
dnl * 3. The end-user documentation included with the redistribution,
dnl * if any, must include the following acknowledgment:
dnl * "This product includes software developed by the
dnl * Kannel Group (http://www.kannel.org/)."
dnl * Alternately, this acknowledgment may appear in the software itself,
dnl * if and wherever such third-party acknowledgments normally appear.
dnl *
dnl * 4. The names "Kannel" and "Kannel Group" must not be used to
dnl * endorse or promote products derived from this software without
dnl * prior written permission. For written permission, please
dnl * contact org@kannel.org.
dnl *
dnl * 5. Products derived from this software may not be called "Kannel",
dnl * nor may "Kannel" appear in their name, without prior written
dnl * permission of the Kannel Group.
dnl *
dnl * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
dnl * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
dnl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
dnl * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
dnl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
dnl * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
dnl * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
dnl * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
dnl * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
dnl * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
dnl * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dnl * ====================================================================
dnl *
dnl * This software consists of voluntary contributions made by many
dnl * individuals on behalf of the Kannel Group. For more information on
dnl * the Kannel Group, please see .
dnl *
dnl * Portions of this software are based upon software originally written at
dnl * WapIT Ltd., Helsinki, Finland for the Kannel project.
dnl */
dnl
dnl configure.in -- main autoconf macro definition file
dnl
dnl Process this file with autoconf to produce a configure script.
dnl
dnl initialization
AC_PREREQ(2.5)
AC_INIT(gw/alt_charsets.h)
AC_CONFIG_HEADER(gw-config.h)
AC_SUBST(SHELL)
AC_CONFIG_AUX_DIR(.)
AC_SET_TERMINAL_SEQUENCES()
AC_CONFIG_NICE(config.nice)
dnl Check gateway version number.
VERSION=`head -n 1 VERSION`
if test "x$VERSION" = "xcvs"; then
AC_MSG_CHECKING([cvs checkout date])
AC_CVS_DATE(CVS_DATE)
AC_MSG_RESULT([$CVS_DATE])
VERSION="$VERSION-$CVS_DATE"
fi
AC_DEFINE_UNQUOTED(GW_NAME, "Kannel")
AC_DEFINE_UNQUOTED(GW_VERSION, "$VERSION")
AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
AC_SUBST(GW_VERSION)
AC_SUBST(VERSION)
AC_CONFIG_SECTION([Configuring for Kannel gateway version $VERSION])
dnl Solaris pkgadd support definitions
PKGADD_PKG="KANNELgateway"
PKGADD_NAME="Kannel - WAP and SMS gateway"
PKGADD_VENDOR="www.kannel.org"
AC_SUBST(PKGADD_PKG)
AC_SUBST(PKGADD_NAME)
AC_SUBST(PKGADD_VENDOR)
dnl Target installation directory for documentation
AC_SUBST(docdir)
docdir='${prefix}/share/doc/kannel'
dnl Checks system type.
AC_CONFIG_SECTION([Running system checks])
AC_CANONICAL_HOST
dnl Checks for programs.
AC_PROG_CC
AC_PROG_CC_C99
if test "$ac_cv_prog_cc_c99" = "no"; then
AC_MSG_ERROR(["Kannel requires a C compiler that supports ISO C99."])
fi
AC_PROG_INSTALL
AC_PROG_RANLIB
AC_PROG_YACC
AC_PROG_LEX
AC_CHECK_TOOL(AR, ar)
AC_PATH_PROG(CONVERT, convert)
AC_PATH_PROG(PERL, perl)
dnl Apply system specific rules.
dnl Executable extension for systems that need one, i.e. Cygwin
dnl Set the LIBTOOL to be used to create libs
EXE_EXT=""
LIBTOOL="$AR rc"
case "$host" in
*-sun-solaris*)
CFLAGS="$CFLAGS -DSunOS=1"
;;
*-cygwin*)
EXE_EXT=".exe"
;;
*apple-darwin*)
# MacOS X
# Lets try to find the newest installed SDK for compilation
# so we know how to link against it.
# If we find a SDK, we use that rather then the standard /usr
# location libs and includes.
found=0
SDK=""
for loc in "MacOSX10.5.sdk" "MacOSX10.4u.sdk" "MacOSX10.4.0.sdk" "MacOSX10.3.9.sdk" \
"MacOSX10.3.0.sdk" "MacOSX10.2.8.sdk" "MacOSX10.1.5.sdk"
do
if test "$found" = "0" ; then
if test -d "/Developer/SDKs/${E}" ; then
found="1"
SDK="${loc}"
fi
fi
done
if test "$SDK" != "" ; then
CFLAGS="$CFLAGS -DDARWIN=1 -L/Developer/SDKs/${SDK}/usr/lib -I/Developer/SDKs/${SDK}/usr/include"
else
CFLAGS="$CFLAGS -DDARWIN=1"
fi
LIBTOOL="libtool -static -o"
;;
*-linux-*)
CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE"
LDFLAGS="$LDFLAGS -rdynamic"
;;
*-*-openbsd* | *-*-freebsd*)
CFLAGS="$CFLAGS -pthread"
AC_CHECK_LIB(c_r, pthread_exit, [LIBS="$LIBS -lc_r"; pthread="yes"])
AC_CHECK_LIB(kse, pthread_exit, [LIBS="$LIBS -lkse"; pthread="yes"])
;;
esac
AC_SUBST(EXE_EXT)
AC_SUBST(LIBTOOL)
AC_ARG_WITH(cflags,
[ --with-cflags=FLAGS use FLAGS for CFLAGS],
CFLAGS="$CFLAGS $withval")
AC_ARG_WITH(libs,
[ --with-libs=FLAGS use FLAGS for extra libraries],
LIBS="$LIBS $withval")
dnl Check whether compiler supports inline
AC_C_INLINE
dnl Check for how to do large files
AC_SYS_LARGEFILE(CFLAGS)
if test "${ac_cv_sys_file_offset_bits}" != no ; then
CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=${ac_cv_sys_file_offset_bits}"
fi
if test "${ac_cv_sys_large_files}" != no ; then
CFLAGS="$CFLAGS -D_LARGE_FILES=${ac_cv_sys_large_files}"
fi
dnl Check for word sizes.
AC_CHECK_SIZEOF(short, 2)
AC_CHECK_SIZEOF(int, 4)
AC_CHECK_SIZEOF(long, 4)
AC_CHECK_SIZEOF(long long, 8)
SIZEOF_SHORT=$ac_cv_sizeof_short
SIZEOF_INT=$ac_cv_sizeof_int
SIZEOF_LONG=$ac_cv_sizeof_long
SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long
AC_SUBST(SIZEOF_SHORT)
AC_SUBST(SIZEOF_INT)
AC_SUBST(SIZEOF_LONG)
AC_SUBST(SIZEOF_LONG_LONG)
dnl Checks for libraries.
AC_CHECK_LIB(m, log)
AC_CHECK_LIB(socket, accept)
AC_CHECK_LIB(nsl, inet_ntoa)
AC_CHECK_LIB(resolv, inet_ntop)
AC_CHECK_LIB(bind, inet_ntop)
if test -z "$pthread"; then
AC_CHECK_LIB(pthread, pthread_exit, [LIBS="$LIBS -lpthread"])
fi
AC_CHECK_LIB(iconv, libiconv, [LIBS="$LIBS -liconv"])
dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(sys/ioctl.h sys/time.h sys/types.h unistd.h sys/poll.h)
AC_CHECK_HEADERS(pthread.h getopt.h syslog.h iconv.h zlib.h execinfo.h stdlib.h)
AC_CHECK_HEADERS([sys/socket.h sys/sockio.h netinet/in.h])
AC_CHECK_HEADERS([net/if.h], [], [],
[#include
#if STDC_HEADERS
# include
# include
#else
#if HAVE_STDLIB_H
# include
# endif
#endif
#if HAVE_SYS_SOCKET_H
# include
#endif
])
dnl Checks for typedefs, structures, and compiler characteristics.
AC_TRY_COMPILE(, [char *func = __FUNCTION__;],
AC_DEFINE(HAVE___FUNCTION__))
AC_TRY_COMPILE(, [char *func = __func__;],
AC_DEFINE(HAVE___FUNC__))
dnl Checks for library functions.
AC_CHECK_FUNCS(gettimeofday select socket strdup getopt_long localtime_r gmtime_r backtrace srandom)
AC_CHECK_FUNC(getopt, [], [AC_LIBOBJ([utils/attgetopt])])
dnl Check if we have reentrant gethostbyname and which one
AC_CHECK_FUNC(gethostbyname_r, [ AC_FUNC_WHICH_GETHOSTBYNAME_R ], [
AC_CHECK_FUNC(gethostbyname,[], [
AC_MSG_ERROR([Couldnot find gethostbyname_r nor gethostbyname functions])])]
)
dnl Extra feature checks
dnl GW_HAVE_TYPE_FROM(HDRNAME, TYPE, HAVENAME, DESCRIPTION)
AC_DEFUN(GW_HAVE_TYPE_FROM, [
AC_CACHE_CHECK([for $2 in <$1>], gw_cv_type_$3,
AC_TRY_COMPILE([#ifdef HAVE_SYS_TYPES_H
#include
#endif
#include <$1>
], [$2 foo;],
gw_cv_type_$3=yes, gw_cv_type_$3=no))
if test $gw_cv_type_$3 = yes; then
AC_DEFINE($3, 1, $4)
fi
])
dnl GW_HAVE_FUNC_FROM(HDRNAME, FUNC, HAVENAME, DESCRIPTION)
AC_DEFUN(GW_HAVE_FUNC_FROM, [
AC_CACHE_CHECK([for $2 in <$1>], gw_cv_func_$3,
AC_TRY_COMPILE([#include <$1>], [void *foo = $2;],
gw_cv_func_$3=yes, gw_cv_func_$3=no))
if test $gw_cv_func_$3 = yes; then
AC_DEFINE($3, 1, $4)
fi
])
GW_HAVE_TYPE_FROM(sys/socket.h,
socklen_t,
HAVE_SOCKLEN_T,
[Defined if there is a socklen_t in ])
GW_HAVE_FUNC_FROM(stdio.h, getopt, HAVE_GETOPT_IN_STDIO_H,
[Does declare getopt()?])
GW_HAVE_FUNC_FROM(unistd.h, getopt, HAVE_GETOPT_IN_UNISTD_H,
[Does declare getopt()?])
dnl POSIX regular expression check
AC_CHECK_HEADERS(regex.h, [
AC_CHECK_FUNC(regcomp, [
AC_DEFINE(HAVE_REGEX)
has_posix_regex=1
])
])
dnl Misfeature checks
AC_CONFIG_SECTION([Checking for POSIX threads support])
AC_MSG_CHECKING(for working pthreads)
AC_TRY_RUN([#include
#include
int pid;
void testpid(void* foo);
int main(void){
pthread_t child;
pid=getpid();
pthread_create(&child,NULL,(void*)testpid,NULL);
pthread_join(child,NULL);
return 0;
}
void testpid(void* foo){
int mypid=getpid();
if(mypid!=pid){
/* Pthreads states that all threads should have the same PID
* we dont!
*/
exit(1);
}else{
exit(0);
}
}
],echo yes , echo no ;CFLAGS="$CFLAGS -DBROKEN_PTHREADS=1", echo Cross compiling - assuming they work)
dnl
dnl Checking pthread_spin support
dnl
AC_MSG_CHECKING([for pthread_spinlock support])
AC_TRY_COMPILE([#include ], [
pthread_spinlock_t lock;
pthread_spin_init(&lock, 0);
pthread_spin_lock(&lock);
pthread_spin_unlock(&lock);
pthread_spin_destroy(&lock);
], [AC_MSG_RESULT(yes); AC_DEFINE(HAVE_PTHREAD_SPINLOCK_T)], AC_MSG_RESULT(no))
dnl checking pthread_rwlock support
AC_MSG_CHECKING([for pthread_rwlock support])
AC_TRY_COMPILE([#include ], [
pthread_rwlock_t lock;
pthread_rwlock_init(&lock, NULL);
pthread_rwlock_rdlock(&lock);
pthread_rwlock_unlock(&lock);
pthread_rwlock_wrlock(&lock);
pthread_rwlock_unlock(&lock);
pthread_rwlock_destroy(&lock);
], [AC_MSG_RESULT(yes); AC_DEFINE(HAVE_PTHREAD_RWLOCK)], AC_MSG_RESULT(no), [
AC_MSG_RESULT(Cross compiling - assuming suuported) ; AC_DEFINE(HAVE_PTHREAD_RWLOCK)])
dnl checking for native semaphore support
dnl Solaris & HP-UX needs librt.
AC_CHECK_LIB(rt, sem_init)
AC_MSG_CHECKING([for semaphore support])
AC_TRY_RUN([#include
int main(void) {
sem_t s;
int val;
/* DARWNIN doesn't implement native sem_init */
if (sem_init(&s, 0, 1) != 0)
return 1;
sem_wait(&s);
sem_post(&s);
sem_getvalue(&s, &val);
sem_destroy(&s);
return 0;
}
], [AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SEMAPHORE)], AC_MSG_RESULT(no), [
AC_MSG_RESULT(Cross compiling - assuming suuported) ; AC_DEFINE(HAVE_SEMAPHORE)])
dnl Check if we have libxml2 installed and which version it is.
dnl Kannel requires currently at least version 2.6.0 of libxml2.
AC_CONFIG_SECTION([Checking for libxml2 support])
xml_ver_required="2.6.0"
AC_PATH_PROGS(XML_CONFIG, xml2-config xml-config, no)
if test "$XML_CONFIG" = "no"; then
AC_MSG_ERROR([You MUST have the libxml2 (aka gnome-xml) library installed])
else
AC_MSG_CHECKING([libxml version])
xml_version=`$XML_CONFIG --version`
AC_MSG_RESULT([$xml_version])
AC_CHECK_VERSION($xml_version, $xml_ver_required,
[ LIBS="$LIBS `$XML_CONFIG --libs`"
CFLAGS="$CFLAGS `$XML_CONFIG --cflags`"
],[
AC_MSG_ERROR([libxml2 version $xml_version is too old. You need at least $xml_ver_required])
])
fi
dnl Implement the --enable-pcre option. This will set HAVE_PCRE in gw-config.h
dnl accordingly and enable the usage of Perl compatible regular expressions.
dnl As POSIX regex is a subset of PCRE, we map the posixpcre API calls, so
dnl HAVE_REGEX has to be undefined.
AC_CONFIG_SECTION([Configuring for PCRE support])
AC_MSG_CHECKING([whether to compile with PCRE support])
AC_ARG_ENABLE(pcre,
[ --enable-pcre enable PCRE regex support @<:@disabled@:>@], [
if test "$enableval" != yes; then
AC_MSG_RESULT(disabled)
else
AC_MSG_RESULT(searching)
AC_PATH_PROGS(PCRE_CONFIG, pcre-config, no)
if test "$PCRE_CONFIG" = "no"; then
AC_MSG_ERROR(Unable to find pcre-config in path for PCRE support)
else
AC_MSG_CHECKING([PCRE version])
pcre_version=`$PCRE_CONFIG --version`
AC_MSG_RESULT([$pcre_version])
LIBS="$LIBS `$PCRE_CONFIG --libs-posix`"
CFLAGS="$CFLAGS `$PCRE_CONFIG --cflags-posix`"
AC_MSG_CHECKING([for POSIX regex provider])
AC_MSG_RESULT([PCRE library])
AC_CHECK_HEADERS(pcreposix.h)
AC_CHECK_LIB(pcreposix, regcomp)
AC_CHECK_HEADERS(pcre.h)
AC_CHECK_FUNCS(pcre_compile)
AC_DEFINE(HAVE_PCRE)
AC_DEFINE_UNQUOTED(LIBPCRE_VERSION, "$pcre_version")
PCRE="yes"
fi
fi
],[
AC_MSG_RESULT(disabled)
])
dnl DocBook stuff
AC_CONFIG_SECTION([Configuring DocBook support])
AC_CHECK_PROG(JADE, jade, jade, no)
AC_CHECK_PROG(JADETEX, jadetex, jadetex, no)
AC_CHECK_PROG(PDFJADETEX, pdfjadetex, pdfjadetex, no)
AC_CHECK_PROG(DVIPS, dvips, dvips, no)
AC_CHECK_PROG(FIG2DEV, fig2dev, fig2dev, no)
AC_CHECK_PROG(CONVERT, convert, convert, no)
AC_SUBST(HTML_DSL)
found=""
for loc in /usr /usr/local; do
if test "x$found" = "x" ; then
for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl \
${loc}/lib/sgml/stylesheets/nwalsh-modular/html/docbook.dsl \
${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/html/docbook.dsl \
${loc}/share/sgml/docbook/dsssl-stylesheets/html/docbook.dsl \
${loc}/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl \
${loc}/share/sgml/docbook/dsssl/modular/html/docbook.dsl ; do
if test "x$found" = "x" ; then
AC_CHECK_FILE($file,HTML_DSL=$file; found=1)
fi
done
fi
done
AC_SUBST(TEX_DSL)
found=""
for loc in /usr /usr/local; do
if test "x$found" = "x" ; then
for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl \
${loc}/lib/sgml/stylesheets/nwalsh-modular/print/docbook.dsl \
${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/print/docbook.dsl \
${loc}/share/sgml/docbook/dsssl-stylesheets/print/docbook.dsl \
${loc}/share/sgml/docbook/stylesheet/dsssl/modular/print/docbook.dsl \
${loc}/share/sgml/docbook/dsssl/modular/print/docbook.dsl ; do
if test "x$found" = "x" ; then
AC_CHECK_FILE($file,TEX_DSL=$file; found=1)
fi
done
fi
done
dnl Implement --enable-warnings option.
AC_ARG_ENABLE(warnings,
[ --enable-warnings enable compilation warnings @<:@disabled@:>@], [
echo enabling compilation warnings
if test -n "$GCC"; then
CFLAGS="$CFLAGS -Wall"
CFLAGS="$CFLAGS -Wmissing-prototypes"
CFLAGS="$CFLAGS -Wmissing-declarations"
CFLAGS="$CFLAGS -Wnested-externs"
CFLAGS="$CFLAGS -Winline"
CFLAGS="$CFLAGS -Wformat -Wformat-security -Wmissing-format-attribute"
#CFLAGS="$CFLAGS -Wstrict-prototypes"
#CFLAGS="$CFLAGS -Wredundant-decls"
#CFLAGS="$CFLAGS -Wconversion"
fi
])
dnl Implement --enable-docs option.
AC_SUBST(DOCSTARGET)
AC_ARG_ENABLE(docs,
[ --enable-docs enable building of documentation @<:@enabled@:>@], [
if test "$enableval" = "yes"
then
DOCSTARGET="docs"
else
DOCSTARGET="no-docs"
fi
])
if test "x$HTML_DSL" = "x" -o "x$TEX_DSL" = "x" \
|| test "$JADE" = "no" \
|| test "$JADETEX" = "no" \
|| test "$PDFJADETEX" = "no" \
|| test "$DVIPS" = "no" \
|| test "$FIG2DEV" = "no" \
|| test "$CONVERT" = "no" \
|| test "$DOCSTARGET" = "no-docs"
then
DOCSTARGET="no-docs"
else
DOCSTARGET="docs"
fi
case "$DOCSTARGET" in
no-docs) AC_MSG_RESULT(Not building documentation.) ;;
docs) AC_MSG_RESULT(Documentation will be built as well.) ;;
esac
dnl Implement --enable-drafts option.
AC_SUBST(DOCDRAFTS)
DOCDRAFTS="IGNORE"
AC_ARG_ENABLE(drafts,
[ --enable-drafts enable building of documentation drafts @<:@disabled@:>@], [
if test "$enableval" = "yes"
then
DOCDRAFTS="INCLUDE"
else
DOCDRAFTS="IGNORE"
fi
])
if test "x$DOCSTARGET" = "xdocs"
then
case "$DOCDRAFTS" in
INCLUDE) AC_MSG_RESULT(Documentation will include drafts.) ;;
esac
fi
AC_CONFIG_SECTION([Configuring parameters])
dnl Implement --with-suffix=version option.
SUFFIX=""
AC_ARG_WITH(suffix,
[ --with-suffix=VERSION set suffix for binaries @<:@foobox-VERSION@:>@], [
if test "x$withval" != "x" ; then
SUFFIX=$withval
fi
])
dnl Implement --enable-suffix option.
AC_ARG_ENABLE(suffix,
[ --enable-suffix enable suffix for binaries @<:@disabled@:>@], [
if test "$enableval" = "yes" ; then
SUFFIX="-$VERSION"
else
SUFFIX=""
fi
])
if test "x$SUFFIX" != "x" ; then
AC_MSG_CHECKING(whether to append suffix to binary)
AC_MSG_RESULT($SUFFIX)
fi
AC_DEFINE_UNQUOTED(SUFFIX, "$SUFFIX")
AC_SUBST(SUFFIX)
dnl Implement --with-defaults=speed/debug option.
AC_ARG_WITH(defaults,
[ --with-defaults=OPTION set default configure options: speed/debug @<:@speed@:>@
this will set assertion checking and malloc wrapper accordingly
speed = native malloc + no assertions
debug = checking malloc + assertions], [
case "$withval" in
speed) assertiondefault=no
mallocdefault=native
;;
debug) assertiondefault=yes
mallocdefault=check
;;
*) echo "unknown --with-defaults parameter $withval"
exit 1
;;
esac
], [
dnl defaults to native malloc but with assertions
assertiondefault=yes
mallocdefault=native
])
dnl Implement --with-malloc=[native|check|slow] option.
AC_MSG_CHECKING(which malloc to use)
AC_ARG_WITH(malloc,
[ --with-malloc=OPTION select malloc wrapper to use: native/check/slow @<:@native@:>@], [
case "$withval" in
native) AC_DEFINE(USE_GWMEM_NATIVE)
AC_MSG_RESULT(native malloc)
;;
check) AC_DEFINE(USE_GWMEM_CHECK)
AC_MSG_RESULT(checking malloc)
;;
slow) AC_DEFINE(USE_GWMEM_SLOW)
AC_MSG_RESULT(slow malloc)
;;
*) echo "Unknown malloc wrapper $withval. Oops."; exit 1 ;;
esac
], [
case "$mallocdefault" in
check) AC_DEFINE(USE_GWMEM_CHECK)
AC_MSG_RESULT(checking malloc)
;;
slow) AC_DEFINE(USE_GWMEM_SLOW)
AC_MSG_RESULT(slow malloc)
;;
*) AC_DEFINE(USE_GWMEM_NATIVE)
AC_MSG_RESULT(native malloc)
;;
esac
])
dnl Implement --disable-assertions option.
AC_ARG_ENABLE(assertions,
[ --disable-assertions turn off assertion checking], [
if test "$enableval" = "no"
then
echo disabling assertion checking
AC_DEFINE(NO_GWASSERT)
fi
], [
if test "$assertiondefault" = "no"
then
echo disabling assertion checking
AC_DEFINE(NO_GWASSERT)
fi
])
dnl Implement the --enable-pam option.
AC_ARG_ENABLE(pam,
[ --enable-pam enable PAM authentication @<:@disabled@:>@], [
if test "$enableval" = "yes"
then
AC_CHECK_LIB(pam, pam_end)
AC_CHECK_LIB(dl,main)
AC_CHECK_HEADERS(security/pam_appl.h)
PAMTARGET="pam"
else
PAMTARGET="no-pam"
fi
])
case "$PAMTARGET" in
no-pam) echo PAM authentication is disabled. ;;
pam) echo PAM authentication is enabled. ;;
esac
dnl Implement --enable-debug option.
AC_ARG_ENABLE(debug,
[ --enable-debug enable non-reentrant debugging for wmls compiler @<:@disabled@:>@], [
echo enabling WMLScript compiler debugging
if test -n "$GCC"; then
CFLAGS="$CFLAGS -Wall"
fi
AC_DEFINE(WS_DEBUG)
])
dnl Implement --enable-localtime option.
AC_ARG_ENABLE(localtime,
[ --enable-localtime log file time stamps in local time, not GMT @<:@enabled@:>@], [
if test "$enableval" = yes; then
echo enabling local time
AC_DEFINE(LOG_TIMESTAMP_LOCALTIME)
fi
],[
echo enabling local time
AC_DEFINE(LOG_TIMESTAMP_LOCALTIME)
])
dnl --enable-mutex-stats option.
AC_ARG_ENABLE(mutex-stats,
[ --enable-mutex-stats produce information about lock contention], [
if test "$enableval" = yes; then
AC_DEFINE(MUTEX_STATS)
fi
])
dnl --disable-cookies option.
AC_ARG_ENABLE(cookies,
[ --disable-cookies disable cookie support for WSP @<:@enabled@:>@], [
if test "$enableval" = yes; then
echo enabling cookies
AC_DEFINE(ENABLE_COOKIES)
else
echo disabling cookies
fi
],[
echo enabling cookies
AC_DEFINE(ENABLE_COOKIES)
])
dnl --disable-keepalive option.
AC_ARG_ENABLE(keepalive,
[ --disable-keepalive disable HTTP/1.1 keep-alive support @<:@enabled@:>@], [
if test "$enableval" = yes; then
echo enabling HTTP/1.1 keep-alive
AC_DEFINE(USE_KEEPALIVE)
else
echo disabling HTTP/1.1 keep-alive
fi
],[
echo enabling HTTP/1.1 keep-alive
AC_DEFINE(USE_KEEPALIVE)
])
dnl --enable-start-stop-daemon option.
AC_ARG_ENABLE(start-stop-daemon,
[ --enable-start-stop-daemon compile the start-stop-daemon program @<:@disabled@:>@], [
if test "$enableval" = yes; then
STARTSTOPDAEMONSRC="utils/start-stop-daemon.c"
fi
])
AC_SUBST(STARTSTOPDAEMONSRC)
dnl Implement --disable-wap and --disable-sms options.
AC_ARG_ENABLE(wap,
[ --disable-wap disables WAP gateway parts in bearerbox], [
if test "$enableval" = "no"
then
echo disabling WAP gateway parts in bearerbox
AC_DEFINE(NO_WAP)
fi
])
AC_ARG_ENABLE(sms,
[ --disable-sms disables SMS gateway parts in bearerbox], [
if test "$enableval" = "no"
then
echo disabling SMS gateway parts in bearerbox
AC_DEFINE(NO_SMS)
fi
])
dnl Implement the --with-ssl option.
AC_CONFIG_SECTION([Configuring OpenSSL support])
AC_ARG_WITH(ssl,
[ --with-ssl[=DIR] where to look for OpenSSL libs and header files
DIR points to the installation @<:@/usr/local/ssl@:>@],
[ if test -d "$withval"; then
ssllib="$withval/lib";
sslinc="$withval/include"
else
AC_MSG_ERROR(Unable to find OpenSSL libs and/or directories at $withval)
fi
])
dnl Implement --enable-ssl option.
AC_MSG_CHECKING([whether to compile with SSL support])
AC_ARG_ENABLE(ssl,
[ --enable-ssl enable SSL client and server support @<:@enabled@:>@], [
if test "$enableval" = no ; then
AC_MSG_RESULT(disabled)
ssl=no
else
ssl=yes
fi
],[
ssl=yes
])
if test "$ssl" = "yes" ; then
dnl test only if --with-ssl has not been used
if test "x$ssllib" = "x" && test "x$sslinc" = "x"; then
for loc in /usr/lib /usr/lib64 /usr/local/ssl/lib /usr/local/openssl/lib; do
if test -f "$loc/libssl.a" -o -f "$loc/libssl.dylib" ; then
ssllib="$loc"
fi
done
for loc in /usr/include/ssl /usr/include/openssl /usr/local/ssl/include \
/usr/local/openssl/include; do
if test -d "$loc"; then
sslinc="$loc"
fi
done
fi
AC_MSG_RESULT(trying $ssllib $sslinc)
fi
dnl Implement the SSL library checking routine.
dnl This will define HAVE_LIBSSL in gw-config.h
if test "x$ssllib" != "x" && test "x$sslinc" != "x"; then
CFLAGS="$CFLAGS -I$sslinc"
LIBS="$LIBS -L$ssllib"
AC_PATH_PROG(OPENSSL, openssl, no)
if test "$OPENSSL" = "yes"; then
AC_MSG_CHECKING([openssl version])
openssl_version=`$OPENSSL version | awk '{print $2}'`
AC_MSG_RESULT([$openssl_version])
fi
AC_CHECK_LIB(crypto, CRYPTO_lock,
[ LIBS="$LIBS -lcrypto"
AC_CHECK_LIB(ssl, SSL_library_init,
[ AC_CHECK_LIB(ssl, SSL_connect)
AC_CHECK_HEADERS(openssl/x509.h openssl/rsa.h openssl/crypto.h \
openssl/pem.h openssl/ssl.h openssl/err.h \
openssl/hmac.h)
AC_MSG_CHECKING(whether the OpenSSL library is multithread-enabled)
AC_TRY_RUN([
#define OPENSSL_THREAD_DEFINES
#include
int main(void) {
#if defined(THREADS)
exit(0);
#elif defined(OPENSSL_THREADS)
exit(0);
#else
exit(1);
#endif
}
], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_LIBSSL)
LIBS="$LIBS -lssl"
AC_MSG_CHECKING([whether to compile with SSL support])
AC_MSG_RESULT(yes)
], [
AC_ARG_ENABLE(ssl-thread-test,
[ --disable-ssl-thread-test disable the multithread test for the OpenSSL library
this will force to continue even if the test fails],
[ if test "$enableval" = no ; then
AC_MSG_RESULT([no, continue forced])
fi
], [
AC_MSG_RESULT(no)
AC_MSG_ERROR(Either get a multithread-enabled SSL or configure with --disable-ssl)
])
], echo "Cross-compiling; make sure your SSL library is multithread-enabled"
)
])
])
fi
AC_CONFIG_SECTION([Configuring DB support])
dnl Implement the --with-mysql option. This will set HAVE_MYSQL in gw-config.h
dnl accordingly and enable the usage of the libmysqlclient routines.
AC_MSG_CHECKING([whether to compile with MySQL support])
AC_ARG_WITH(mysql,
[ --with-mysql enable MySQL storage @<:@disabled@:>@], [
if test "$withval" != yes ; then
AC_MSG_RESULT(disabled)
else
dnl Implement the --with-mysql-dir option.
AC_ARG_WITH(mysql-dir,
[ --with-mysql-dir=DIR where to look for MySQL libs and header files
DIR points to the installation @<:@/usr/local/mysql@:>@],
[
mysqlloc=""
if test -d "$withval" ; then
mysqlloc="$withval"
fi
])
AC_MSG_RESULT(searching)
AC_PATH_PROG(MYSQL_CONFIG, mysql_config, no, [$PATH:$mysqlloc/bin:$mysqlloc])
dnl check for MySQL 4.x style mysql_config information
if test "$MYSQL_CONFIG" = "no"; then
found=""
for loc in $mysqlloc /usr /usr/local ; do
if test "x$found" = "x" ; then
AC_MSG_CHECKING([for MySQL client support in])
AC_MSG_RESULT($loc)
AC_CHECK_FILE("$loc/include/mysql/mysql.h",
[CFLAGS="$CFLAGS -I$loc/include/mysql"; LIBS="$LIBS -L$loc/lib/mysql -lmysqlclient"]; found=1,
[AC_CHECK_FILE("$loc/include/mysql.h",
[CFLAGS="$CFLAGS -I$loc/include"; LIBS="$LIBS -L$loc/lib -lmysqlclient"]; found=1
)]
)
fi
done
if test "x$found" != "x1" ; then
AC_MSG_ERROR([Unable to find mysql.h, please provide a --with-mysql-dir= location])
fi
else
dnl mysql_config found
AC_MSG_CHECKING([mysql version])
mysql_version=`$MYSQL_CONFIG --version`
AC_MSG_RESULT([$mysql_version])
dnl mysql-4.x style
MYSQL_LIBS=""
if $MYSQL_CONFIG --libs_r &>/dev/null ; then
MYSQL_LIBS=`$MYSQL_CONFIG --libs_r`
AC_MSG_CHECKING([mysql reentrant libs])
AC_MSG_RESULT([$MYSQL_LIBS])
AC_CHECK_LIB(mysqlclient_r, mysql_init, [ LIBS="$LIBS $MYSQL_LIBS" ],
[ MYSQL_LIBS="" ], [ $MYSQL_LIBS ])
fi
if test -z "$MYSQL_LIBS" ; then
MYSQL_LIBS=`$MYSQL_CONFIG --libs`
AC_MSG_CHECKING([mysql libs])
AC_MSG_RESULT([$MYSQL_LIBS])
AC_CHECK_LIB(mysqlclient, mysql_init, [ LIBS="$LIBS $MYSQL_LIBS" ],
[AC_MSG_ERROR([Unable to find MySQL client libraries])], [ $MYSQL_LIBS ])
fi
AC_MSG_CHECKING([mysql includes])
dnl mysql-4.x style
if $MYSQL_CONFIG --include &>/dev/null ; then
MYSQL_CFLAGS=`$MYSQL_CONFIG --include`
else
MYSQL_CFLAGS=`$MYSQL_CONFIG --cflags`
fi
CFLAGS="$CFLAGS $MYSQL_CFLAGS"
AC_MSG_RESULT([$MYSQL_CFLAGS])
fi
AC_CHECK_HEADERS(mysql/mysql.h mysql/mysql_version.h)
AC_DEFINE(HAVE_MYSQL)
AC_MSG_CHECKING([whether to compile with MySQL support])
AC_MSG_RESULT(yes)
MYSQL="yes"
fi
],[
AC_MSG_RESULT(disabled)
])
dnl Implement the --with-sdb option. This will set HAVE_SDB in gw-config.h
dnl accordingly and enable the usage of the libsdb routines.
AC_MSG_CHECKING([whether to compile with LibSDB support])
AC_ARG_WITH(sdb,
[ --with-sdb enable LibSDB storage @<:@disabled@:>@], [
if test "$withval" != yes; then
AC_MSG_RESULT(disabled)
else
AC_MSG_RESULT(searching)
AC_PATH_PROGS(SDB_CONFIG, sdb-config, no)
if test "$SDB_CONFIG" = "no"; then
AC_MSG_ERROR(Unable to find sdb-config in path for SDB support)
else
AC_MSG_CHECKING([sdb version])
sdb_version=`$SDB_CONFIG --version`
AC_MSG_RESULT([$sdb_version])
CFLAGS="$CFLAGS `$SDB_CONFIG --cflags`"
AC_CHECK_HEADERS(sdb.h)
LIBS="$LIBS `$SDB_CONFIG --libs`"
AC_CHECK_LIB(sdb, sdb_init,
[LIBS="$LIBS -lsdb"
AC_DEFINE(HAVE_SDB)
AC_DEFINE_UNQUOTED(LIBSDB_VERSION, "$sdb_version")
SDB="yes"],
[AC_MSG_ERROR([Unable to find libSDB client libraries])]
)
fi
fi
],[
AC_MSG_RESULT(disabled)
])
dnl Implement the --with-sqlite2 option. This will set HAVE_SQLITE in gw-config.h
dnl accordingly and enable the usage of the libsqlite routines.
AC_MSG_CHECKING([whether to compile with SQLite2 support])
AC_ARG_WITH(sqlite2,
[ --with-sqlite2 enable SQLite2 storage @<:@disabled@:>@], [
if test "$withval" != yes; then
AC_MSG_RESULT(disabled)
else
AC_MSG_RESULT(searching)
AC_CHECK_HEADERS(sqlite.h)
LIBS="$LIBS -L/usr/local/lib"
AC_CHECK_LIB(sqlite, sqlite_open,
[LIBS="$LIBS -lsqlite"
AC_DEFINE(HAVE_SQLITE)
SQLITE="yes"],
[AC_MSG_ERROR([Unable to find SQLite2 client libraries])]
)
AC_PATH_PROGS(SQLITE, sqlite, no)
if test "$SQLITE" = "no"; then
AC_MSG_WARN([Unable to find sqlite in path for SQLite2 support])
else
AC_MSG_CHECKING([sqlite version])
sqlite_version=`$SQLITE -version`
AC_MSG_RESULT([$sqlite_version])
fi
fi
],[
AC_MSG_RESULT(disabled)
])
dnl Implement the --with-sqlite3 option. This will set HAVE_SQLITE3 in gw-config.h
dnl accordingly and enable the usage of the libsqlite3 routines.
AC_MSG_CHECKING([whether to compile with SQLite3 support])
AC_ARG_WITH(sqlite3,
[ --with-sqlite3 enable SQLite3 storage @<:@disabled@:>@], [
if test "$withval" != yes; then
AC_MSG_RESULT(disabled)
else
AC_MSG_RESULT(searching)
AC_CHECK_HEADERS(sqlite3.h)
LIBS="$LIBS -L/usr/local/lib"
AC_CHECK_LIB(sqlite3, sqlite3_open,
[LIBS="$LIBS -lsqlite3"
AC_DEFINE(HAVE_SQLITE3)
SQLITE3="yes"],
[AC_MSG_ERROR([Unable to find SQLite3 client libraries])]
)
AC_PATH_PROGS(SQLITE3, sqlite3, no)
if test "$SQLITE3" = "no"; then
AC_MSG_WARN([Unable to find sqlite3 in path for SQLite3 support])
else
AC_MSG_CHECKING([sqlite3 version])
sqlite3_version=`$SQLITE3 -version`
AC_MSG_RESULT([$sqlite3_version])
fi
fi
],[
AC_MSG_RESULT(disabled)
])
dnl Implement the --with-oracle option. This will set HAVE_ORACLE in gw-config.h
dnl accordingly and enable the usage of the OCI routines.
AC_MSG_CHECKING([whether to compile with Oracle support])
AC_ARG_WITH(oracle,
[ --with-oracle enable ORACLE storage @<:@disabled@:>@],
[
if test "$withval" != yes ; then
AC_MSG_RESULT(disabled)
else
AC_MSG_RESULT(searching)
AC_ARG_WITH(
oracle-includes,
[ --with-oracle-includes=DIR adds oracle include paths],
[ ORACLE_INCLUDE_PATH="$withval" ],
[ ORACLE_INCLUDE_PATH="$ORACLE_HOME/rdbms/demo $ORACLE_HOME/rdbms/public" ]
)
for a in $ORACLE_INCLUDE_PATH
do
CPPFLAGS="$CPPFLAGS -I$a"
done
AC_MSG_CHECKING([for oci.h ])
AC_TRY_CPP([#include ],AC_MSG_RESULT(yes), AC_MSG_ERROR([oci.h not found]))
CFLAGS="$CFLAGS $CPPFLAGS"
AC_ARG_WITH(
oracle-libs,
[ --with-oracle-libs=DIR adds oracle library path],
[ ORACLE_LIB_PATH="$withval" ],
[ ORACLE_LIB_PATH="$ORACLE_HOME/lib" ]
)
for a in $ORACLE_LIB_PATH
do
LIBS="$LIBS -L$a"
done
dnl Check for Oracle 10g instant client
AC_CHECK_LIB(clntsh,OCIEnvCreate,[ LIBS="$LIBS -lclntsh" ],
AC_CHECK_LIB(clntsh,OCIEnvCreate,[ LIBS="$LIBS -lclntsh -lnnz10" ],exit)
)
dnl Beware that Oracle 10g doesn't use anymore the libwtcX.so libs,
dnl so we don't break hard in case they are not present.
AC_CHECK_LIB(wtc8,wtcstu,[ LIBS="$LIBS -lwtc8" ],
AC_CHECK_LIB(wtc9,wtcstu,[ LIBS="$LIBS -lwtc9" ], true)
)
AC_DEFINE(HAVE_ORACLE, 1, [Do we have Oracle])
AC_MSG_CHECKING([whether to compile with Oracle support])
AC_MSG_RESULT(yes)
fi
],
[AC_MSG_RESULT(disabled)])
dnl Implement the --with-pgsql option. This will set HAVE_PGSQL in gw-config.h
dnl accordingly and enable the usage of the libpq routines.
AC_MSG_CHECKING([whether to compile with PostgresSQL support])
AC_ARG_WITH(pgsql,
[ --with-pgsql enable PostgreSQL storage @<:@disabled@:>@], [
if test "$withval" != yes ; then
AC_MSG_RESULT(disabled)
else
dnl Implement the --with-pgsql-dir option.
AC_ARG_WITH(pgsql-dir,
[ --with-pgsql-dir=DIR where to look for PostgreSQL libs and header files
DIR points to the installation @<:@/usr/local/pgsql@:>@],
[
pgsqlloc=""
if test -d "$withval" ; then
pgsqlloc="$withval"
fi
])
AC_MSG_RESULT(searching)
AC_PATH_PROG(PGSQL_CONFIG, pg_config, no, [$PATH:$pgsqlloc/bin:$pgsqlloc:/usr/lib/postgresql/bin])
dnl check for PgSQL >= 7.2 style pg_config information
if test "$PGSQL_CONFIG" = "no"; then
found=""
for loc in $pgsqlloc /usr /usr/local ; do
if test "x$found" = "x" ; then
AC_MSG_CHECKING([for PostgresSQL include files in])
AC_MSG_RESULT($loc)
AC_CHECK_FILE("$loc/include/postgresql/libpq-fe.h",
[CFLAGS="$CFLAGS -I$loc/include/postgresql"; LIBS="$LIBS -L$loc/lib/postgresql -lpq"]; found=1,
[AC_CHECK_FILE("$loc/include/pgsql/libpq-fe.h",
[CFLAGS="$CFLAGS -I$loc/include/pgsql"; LIBS="$LIBS -L$loc/lib/pgsql -lpq"]; found=1,
[AC_CHECK_FILE("$loc/pgsql/include/libpq-fe.h",
[CFLAGS="$CFLAGS -I$loc/pgsql/include"; LIBS="$LIBS -L$loc/pgsql/lib -lpq"]; found=1,
)]
)])
fi
done
if test "x$found" != "x1" ; then
AC_MSG_ERROR([Unable to find libpq-fe.h, please provide a --with-pgsql-dir= location])
fi
else
dnl pg_config found
AC_MSG_CHECKING([PostgreSQL version])
pgsql_version=`$PGSQL_CONFIG --version`
AC_MSG_RESULT([$pgsql_version])
AC_MSG_CHECKING([PostgreSQL libs])
if $PGSQL_CONFIG --libdir &>/dev/null ; then
LIBS="$LIBS -L`$PGSQL_CONFIG --libdir`"
pg_libdir=`$PGSQL_CONFIG --libdir`
AC_MSG_RESULT([$pg_libdir])
fi
AC_MSG_CHECKING([PostgreSQL includes])
if $PGSQL_CONFIG --includedir &>/dev/null ; then
CFLAGS="$CFLAGS -I`$PGSQL_CONFIG --includedir`"
pg_incdir=`$PGSQL_CONFIG --includedir`
AC_MSG_RESULT([$pg_incdir])
fi
fi
AC_CHECK_HEADERS(postgresql/libpq-fe.h)
AC_CHECK_LIB(pq, PQconnectdb, [])
AC_DEFINE(HAVE_PGSQL)
AC_MSG_CHECKING([whether to compile with PostgreSQL support])
AC_MSG_RESULT(yes)
PGSQL="yes"
fi
],[
AC_MSG_RESULT(disabled)
])
dnl Implement the --with-wtls option.
dnl Check to see if we should include WTLS support, and which library to use.
AC_ARG_WITH(wtls,
[ --with-wtls@<:@=TYPE@:>@ select WTLS version to use: openssl/baltimore],
[ AC_CONFIG_SECTION([Configuring WTLS support])
AC_MSG_CHECKING([for WTLS library])
AC_MSG_RESULT($withval)
case "$withval" in
openssl)
AC_CHECK_LIB(crypto, RSA_new,
[ AC_CHECK_HEADERS(openssl/objects.h openssl/rc5.h,
AC_DEFINE(HAVE_WTLS_OPENSSL),
AC_MSG_WARN(OpenSSL installation seems to lack RC5 algorithm!)
)
])
;;
baltimore)
AC_MSG_ERROR(This WTLS library is yet not supported!)
;;
*)
AC_MSG_ERROR(Unknown WTLS libary support!)
exit 1
;;
esac
])
dnl Final Output
AC_CONFIG_SECTION([Generating output files])
AC_OUTPUT(gwlib/gw_uuid_types.h Makefile)
dnl LICENSE notice
AC_CONFIG_SECTION([License information])
cat < |
+--------------------------------------------------------------------+
Thank you for using Kannel.
X
gateway-1.4.3/LICENSE 0000644 0001750 0001750 00000005317 11132672005 013226 0 ustar soren soren /* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2009 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
gateway-1.4.3/doc/ 0000755 0001750 0001750 00000000000 11142334236 012762 5 ustar soren soren gateway-1.4.3/doc/ChangeLog-1.1.4 0000644 0001750 0001750 00000047633 07525470177 015227 0 ustar soren soren 2001-05-07 Richard Braakman
* Making release 1.1.4.
2001-05-07 Richard Braakman
* gwlib/list.h: list_len(NULL) returns 0. This has been true
for some time now. Make it part of the documented interface.
2001-05-07 Richard Braakman
* gwlib/octstr.[ch]: Added octstr_dump_short() for dumping octstrs
that are expected to be short printable strings. The output is
much shorter for such strings, but the function can still handle
any kind of octstr.
* gwlib/smpp_pdu.c: Made smpp_pdu_dump() use octstr_dump_short().
2001-05-07 Richard Braakman
* Updated NEWS file.
2001-05-07 Uoti Urpala
* gw/smsc_emi2.c: Changed error handling for (re)opening
connections, reorganized some code.
2001-05-07 Richard Braakman
* gw/smsc_smpp.c: Use system-type for receiver as well as transmitter.
2001-05-06 Richard Braakman
* gwlib/octstr.c: Fix edge cases in octstr_get_bits and
octstr_set_bits.
2001-05-04 Richard Braakman
* gw/smsc_cimd2.c: Made packet_encode_message() cope if the
sender field is not set.
2001-05-04 Richard Braakman
* configure.in, configure: Made libxml version check require
2.2.5 again, and added some output about the check.
2001-05-04 Aarno Syvnen
* gw/wap_push_pap_compiler.c: Fixed an uninitialised variable
2001-05-03 Tuomas Luttinen
* gw/wml_compiler.c (parse_text): A bug fix: added a check that around
text emphasis the white space is not removed.
2001-05-03 Lars Wirzenius
* Makefile.in, configure.in: applied patch from Craig Emery to
slightly improve (and simplify!) building and configuring.
2001-05-03 Lars Wirzenius
* gw/smsbox.c: Log username (at info level) whenever someone
uses the sendsms service. Based on request from Johan du Buson.
* gw/smsc_smpp.c: The transmitter thread is woken up as soon as
there is something to send. Previously it woke up only when it
was time to send the next enquire_link PDU. This was slighly slow.
* test/drive_smpp.c: Deal with enquire_link PDUs.
2001-05-03 Lars Wirzenius
* gw/smsc_smpp.c: Implemented system-type and address-range
variables from the config file. In the I/O thread, timeouts
are calculated to the next time when enquire_link needs to be
sent, instead of using 1.0 seconds always. Configuration file
is checked that it specifies smsc-username and smsc-password.
* test/drive_smpp.conf: Added missing smsc-username and
smsc-password.
2001-05-03 Lars Wirzenius
* gw/smsc_smpp.c: Partly rewritten to use a simpler thread
structure and to deal with I/O errors (such as broken
connections). Most of the code is the same, but it has been
rearranged.
* test/test_smsc.c, gwlib/date.[ch]: Moved function
date_universal_now from test_smsc.c to date.c.
2001-05-03 Aarno Syvnen
* gw/wap_push_pap_compiler.[ch]: A compiler for compiling pap control
messages to wap events.
* gw/wap_push_ppg.c: Do not panic, when pi message does not not have
any headers (a warning instead). Corrected a misspelling. Use prefix
PAP in all enumerations defined by pap protocol.
* gw/wap_push_ppg.h: Another misspelling corrected. Hnadle default
values of pap attributes (by reordering, so that the numeric equi-
valent of an attribute has value 0).
* gw/wap_push_pap.c: A new test version of pap module.
*wap/wap_events.def: Corrected a typo.
2001-05-03 Nick Clarey
* gw/smsc_at.c: Applied patch from Alex Judd (ajudd@snaz.com),
adding an automatic retry to message sending should it fail.
2001-05-02 Richard Braakman
* gw/smsc_cimd2.c: Fix encoding of text messages that have UDH.
(It got the length wrong due to a _probable_ misreading of the
spec. If SMSCs implement what we thought it had said, then we
have a problem.)
2001-05-02 Richard Braakman
* gwlib/octstr.c: Made octstr_get_char() not crash if pos < 0.
It now returns -1 instead.
2001-05-02 Richard Braakman
* gw/wap_push_ppg.h, wap_push_pap.c: Renamed TRUE and FALSE
to PAP_TRUE and PAP_FALSE. (These are enumerated protocol
values.) Needed for portability to systems that predefine
TRUE and FALSE macros.
2001-04-30 Richard Braakman
* gw/smsc_{at,cimd2,ois,smpp}.c, gw/sms.h, gw/smpp_pdu.h:
Standardized on two data coding scheme values, called DCS_GSM_TEXT
and DCS_OCTET_DATA. Not all protocols can use these, but at least
the ones that do will all use the same values. Both have now been
chosen to set only the alphabet, and leave message class alone.
2001-04-29 Derry Hamilton
* configure.in,configure: Allow libxml versions between
2.2.10 and 2.2.19.
2001-04-26 Lars Wirzenius
* gw/smsc.c, gw/smsc_p.h, gw/smsc_smpp.c, gw/smscconn.c,
gw/smscconn_p.h: Converted SMPP driver to use the SMSCConn
interface. This is needed to improve reliablity of the driver,
which will happen next.
2001-04-26 Richard Braakman
* gw/smsc_cimd2.c: Reopen connection if SMSC does not respond
to "alive" request.
2001-04-26 Richard Braakman
* gwlib/http.c: Handle 100-Continue responses.
2001-04-26 Richard Braakman
* gw/smsc_cimd2.c: Stopped sending "delivery request" when
logging in. It is not needed in the normal configuration, and
it confuses some SMSCs. Thanks to Antti Valtokari for tracking
this down. (If it _is_ needed in your configuration, then you
will not get messages that arrived while Kannel wasn't connected.)
* doc/userguide/userguide.xml: Explain what configuration the
cimd2 driver expects from the SMSC.
2001-04-25 Tuomas Luttinen
* configure[.in] : Kannel now requires libxml 2.2.5 or newer. Reasons
for this are: *encondingAliases functions that were included in 2.2.3
*a bug that affects XML attributes in 2.2.3 and 2.2.4
2001-04-25 Uoti Urpala
* gw/smsc_emi2.c, gw/emimsg.c: Changed debugging output, made
reconnections more robust.
2001-04-25 Richard Braakman
* gw/smsc_at.c: In pdu_encode(), revert to using a Protocol-ID
of 0 (implicit) rather than 0x1F (which doesn't seem to be
defined). This might be the key to the problems people have
had with this module. Please let us know.
2001-04-25 Richard Braakman
* doc/TESTCASES: Removed, we have "make check" now.
2001-04-24 Uoti Urpala
* doc/userguide/userguide.xml: Added information about emi2.
2001-04-24 Lars Wirzenius
* gw/smsc_smpp.c, test/test_smsc.c: Implemented sending of
enquire_link packets and handling of their responses. This is
very simplistic, still: It doesn't check that the responses
are actually received. That will have to be implemented later.
2001-04-24 Richard Braakman
* gw/smsc_wrapper.c: Produce an info log when a reconnection
attempt succeeds.
2001-04-23 Lars Wirzenius
* gwlib/octstr.c, test/fakesmsc.c, utils/start-stop-daemon.c,
wap/wsp_push_client_machine.def, wap/wsp_session.c: Applied
manually parts of patch send by Dirk-Willem van Gulik as
improvements for MacOS X. Mainly this included renaming of some
local variables (uint -> ui), presumably because MacOS X defines
uint as a macro. Also reformatted fakesmsc and start-stop-daemon
output and corrected preprocessor syntax.
2001-04-23 Richard Braakman
* gwlib/http.[ch]: Added support for HEAD method, supplied
by Jarkko Kovala.
2001-04-23 Richard Braakman
* gwlib/socket.c: Clear sockaddr_in structure before using it,
to make FreeBSD happier.
2001-04-21 Uoti Urpala
* gw/smsc_emi2.c: Fixed a stupid bug in the previous fix.
2001-04-20 Uoti Urpala
* gw/smsc_emi2.c: Fixed a bug in SMSC time stamp parsing.
2001-04-19 Richard Braakman
* gw/smsbox.c: Fixed bad assertion in prepend_catenation_udh().
2001-04-18 Richard Braakman
* gwlib/gwthread-pthread.c: Made gwthread_join safe.
2001-04-18 Kalle Marjola
* gw/bb_store.c: updated writing to file a bit. Still problem if
messages arrive faster than store_cleanup works, needs to modify
to use hash at some point
* gw/bb_smscconn.c: changed so that when shutting down, ignores
messages that cannot be routed. So if you have not enabled
SMS-store, some messages can be lost.
2001-04-18 Kalle Marjola
* doc/userguide/userguide.xml: fixed some typos
2001-04-17 Uoti Urpala
* gw/smsc_emi2.c, gw/emimsg.[ch]: Added support for operation type
01, other changes to work with different SMSC setups.
2001-04-17 Richard Braakman
* gw/urltrans.c: In strip_keyword(), use the right test for
end of octstr. This fixes handling of messages that only
have the keyword.
2001-04-17 Lars Wirzenius
* gwlib/http.c: When the http module is shut down, set run_status
to limbo so it can be restarted. Paul Keogh wanted this so that
(parts of) Kannel can run as a COM object.
2001-04-17 Lars Wirzenius
* doc/CodingStyle: Added a paragraph about CVS tags.
2001-04-16 Richard Braakman
* gw/wap_push_ota.c: Removed and
includes. They are not used by anything and cause portability
problems.
2001-04-13 Uoti Urpala
* gw/smsbox.c: Bugfix, messages sent with sendsms GET requests
were always marked as binary (this bug was created when sendsms
POST was added).
2001-04-12 Lars Wirzenius
* gw/smsc_smpp.c: Make it optional to dump or not dump SMPP pdus
that are received or sent. Not dumping them reduces "make bench"
log file sizes by about half a gigabyte.
2001-04-12 Kalle Marjola
* gw/urltrans.c (urltrans_get_pattern): fixed that %s cannot cause
overflow if there is catch-all argument
2001-04-11 Richard Braakman
* gw/urltrans.c: Slight simplification of strip_keyword().
2001-04-11 Kalle Marjola
* README: changed smsc interface guidelines to point to
smscconn_p.h
* gw/smsc_interface.def: removed as depricated
* doc/userguide/userguide.xml: fixed typo, it is strip-keyword,
not split-keyword
* gw/urltrans.c: modified strip-keyword function
* gw/bearerbox.c: changed shutdown message a bit when killedby
signal
2001-04-10 Kalle Marjola
* gw/bb_store.c: some little fixes, dumps acks to file, too, if
any in memory
* gw/bb_boxc.c: added some comments for possible future updates
2001-04-10 Kalle Marjola
* gw/bb_store.c: Bugfix: comprasion was wrong way around...
2001-04-10 Kalle Marjola
* gw/bb_store.c: Updated to use double-memory buffering and to do
frequent dumps out of that data. Now it is fast and does not take
much disk space. Interval is currently fixed (5 secs), and there
is still no message queue limitations, and sendsms (push9 messages
are not yet supported. But otherwise it should work.
* gw/bearerbox.c|h: required little modifications
* doc/userguide/userguide.xml: added notes of store-file variable
2001-04-10 Richard Braakman
* gw/smsbox.c: Add no-cache headers to sendsms replies.
2001-04-05 Uoti Urpala
* gwlib/http.c: Fixed a bug in the sending of HTTP replies. It was
unlikely to be triggered with replies as short as Kannel normally
uses, though.
* gwlib/conn.[ch]: The callback function of registered connections
is called when all queued output is sent. This was required for
the above fix.
2001-04-04 Kalle Marjola
* gw/smsbox.c: Bugfix. Fixed memory leak in header parsing
2001-04-03 Richard Braakman
* gwlib/fdset.c: When destroying an fdset with active fd's,
simply ignore those fd's and make it the caller's responsibility
to deal with them. This reverses a change from 2000-11-22, which
was made at the time to fix the http shutdown sequence. It didn't,
and now it's in the way of a better solution.
2001-03-30 Uoti Urpala
* gwlib/http.c: Enabled keepalive connections again.
2001-03-29 Uoti Urpala
* gw/urltrans.c: Test in find_translation() was the wrong way
around, 'accepted-smsc' actually worked like denied-smsc. Fixed.
Also enabled using 'accepted-smsc' in default SMS-service groups.
2001-03-29 Uoti Urpala
* gw/smsc_emi2.c: Added support for the "our-port" parameter.
* gwlib/conn.[ch]: Added function conn_open_tcp_with_port, which
allows specifying the local port number.
2001-03-29 Uoti Urpala
* gwlib/http.c: Added a test that checks whether connections in
the connection pool have been closed before trying to reuse them.
2001-03-28 Uoti Urpala
* gw/smsc_emi2.c: Wrote. New implementation of the emi_ip protocol.
* gw/emimsg.c, gw/emimsg.h: Wrote. Functions for working with EMI
messages. Used by smsc_emi2.c and testing programs which I didn't
add to CVS yet.
* gw/smscconn.c, gw/smscconn_p.h: Modified to recognize the new
smsc type.
2001-03-28 Kalle Marjola
* gw/smsbox.c: added content-type checking in sendsms POST, and
set binary of sms.msgdata accordingly (note: UDH+7bit msgdata
might not work with some SMSC center protocols currently)
2001-03-27 Aarno Syvnen
* gw/wap_push_ppg.c: Fixed a compiler warning
2001-03-27 Kalle Marjola
* gw/smsbox.c: combatibility breaker: do not allow default sendsms
user anymore (guess I thought that that has been disabled years
ago...)
* gw/smsbox.c: added POST support for send-sms, too. Hopefully
works. Use is automatic, if request to Kannel is POST, body is
used as message text, otherwise cgi-args are parsed. Username,
password, receiver number etc. are taken from X-Kannel headers
(like X-Kannel-Password) and are documented real soon...
2001-03-27 Kalle Marjola
* doc/userguide/userguide.txt: added new configuration variables,
but missing X-Kannel header definations. Will add these later.
* gw/smskannel.conf: changed 'url' to 'get-url' (althought plain
url still works, for backward compability)
2001-03-27 Kalle Marjola
* gw/smsbox.c: added post-url support for sms-service
group. Documentation in User's Guide RSN (hopefully)
* gw/urltrans.c: added that strip-keyword with POST is done here,
althougt that is ugly (but easier to do that way)
2001-03-27 Kalle Marjola
* gwlib/cfg.h|c: added new function cfg_get_bool, taking
true/false, on/off, yes/no or 0/1
* urltrans.c: modified to use new bool type with concatenation,
omit-empty and some new variables (theoretical compatibility breaker)
* urltrans.c|h: added new variables for sms-service group:
catch-all (should work as %a or %r in pattern),
accept-x-kannel-headers (see below) and some variables for POST
use
* smsbox.c: Compatibility breaker: modified to allow from, to and
UDH field set by SMS service, as X-Kannel- header, if
accept-x-kannel-headers set for sms-service. The compatibility
breaker is that X-Kannel-UDH does not work anymore unless
accept-x-kannel-headers is set
* smsbox.c: Compatibility breaker: if sms-service HTTP fetch reply
is of content-type application/octet-stream set flag 8bit on. This
can be prevented by setting assume-plain-text on for the service.
2001-03-27 Tuomas Luttinen
* configure.in: Removed the earlier patch, the test was just on the
old implementation, I didn't run autoconf...
2001-03-27 Aarno Syvnen
* gw/wap_push_pap.c|h. Testing version of the pap module
* gw/wap_ppg_push_machine.def, gw/wap_ppg_session_machine.def:
Machines to store push data.
* gw/wap_push_ppg.c|h: push proxy gateway main module
* gw/wap_push_ota.c: Lots of bugfixes. Courtesy to Peter Galluc,
Derry Hamilton and Uoti. (There were other bugs, too.) Trans-
ferred handling of header X-Wap-Application-Id to module ppg.
Fixing memory leaks.
* wap/wap_events.def: push_id removed from Pom-Connect.req.
* gw/wapbox.c: Initing and shutdown of new modules, include new
headers.
* gw/wap-appl.c: Added handling of the event Pom-Connect.req
* wap/wsp_server_session_states.def: Corrected a typo spotted by
Aymerick Jehanne.
* wap/wsp_session.c: Added functions to create events for push
abort and confirmation, fixed bugs in functions make_confirmed_push
pdu and make_push_pdu. Fixed memory leaks.
2001-03-27 Tuomas Luttinen
* configure.in: Replaced the earlier way to detect xml2-config with
patch provided by Craig Emery that is shorter and as effective. Both
were tested with different libxml versions, also with both xml-config
and xml2-config.
2001-03-27 Richard Braakman
* gw/smsbox.c: Fix bad memory management of faked_sender string.
2001-03-26 Richard Braakman
* gw/smsbox.c: Converted some char * to Octstr *.
* gw/smsc_cimd2.c: Changed "const static" to "static const" in
variable declarations (ansification).
* utils/run_kannel_box.c: In print_usage(), actually use the
stream argument instead of always printing to stderr.
2001-03-26 Uoti Urpala
* gw/msg.c: Fixed bug when sizeof(long) != 4, removed unneeded
code.
2001-03-23 Richard Braakman
* gw/smsbox.c: Fix call to alog (urltrans_username returns
Octstr *, not char *). Spotted by Paul Keogh and Gildas PERROT.
2001-03-23 Kalle Marjola
* gw/smscconn_p.h: made interface a bit more clarified and
moved counters to callback
* gw/bb_smscconn.c: added counter increases
* gw/smsc_wrapper.c, gw/smsc_fake.c: removed counter increases
2001-03-23 Kalle Marjola
* gw/smsc_http.c: various little fixes
2001-03-23 Tuomas Luttinen
* utils/kannel-stable-rh*.spec (Requires): Now requires libxml2 >=
libxml2-2.2.0.
2001-03-22 Kalle Marjola
* gw/smsc_http.c: put smsc-id to correct place
2001-03-22 Kalle Marjola
* gw/smsc_http.c: fixed several memory leaks
2001-03-22 Uoti Urpala
* gwlib/http.c: Fixed memory leak.
2001-03-21 Lars Wirzenius
* gwlib/cfg.h: Commented return value policy for octet strings.
2001-03-21 Tuomas Luttinen
* configure.in, configure: Added the xml2-config that libxml-2.3.* and
newer want instead of xml-config. Tested with libxml-2.2.11 and 2.3.4.
Yet to be tested with both libxml1 and libxml2 installed.
2001-03-21 Kalle Marjola
* gwlib/xmlrpc.h|c: Updated, still missing many things
2001-03-21 Kalle Marjola
* gwlib/xmlrpc.h|c: Added. Initial code to implement XML-RPC
specification.
2001-03-21 Lars Wirzenius
* checks/check_http.sh: Kill server via HTTP, instead of via
a signal. This way, if the server has trouble dying properly,
it will be quite visible, instead of possibly hidden by signal
handling.
2001-03-21 Uoti Urpala
* gwlib/http.c: Fixed memory leaks, updated keepalive connections
to work again after Richard's changes (still left them disabled by
default though).
2001-03-21 Uoti Urpala
* gw/bb_smscconn.c: Fixed incorrect test in sms_router, the
smsc_id of a discarded message was logged only if it _was_ NULL.
2001-03-20 Richard Braakman
* gwlib/http.c: Server side now accepts POST requests. This
involved separating the header and body reading code into a
section shared by server and client side.
* Fixed a bug along the way which would cause busy-waiting in the
client code when waiting for a result to arrive.
Also made return codes consistent for the state functions, so
that 0 means completion and 1 means waiting for more input.
gateway-1.4.3/doc/ChangeLog-1.1.2 0000644 0001750 0001750 00000024766 07525470177 015227 0 ustar soren soren 2001-02-26 Richard Braakman
* Making release 1.1.2.
2001-02-23 Peter Grnholm
* userguide: Wrote section "Setting up a dial-up line"
2001-02-21 Richard Braakman
* gw/wap-appl.c: Suppress server-generated error pages if they
are in a format (i.e. text/html) that the client does not accept.
2001-02-21 Richard Braakman
* gw/wap-appl.c: When suppressing an HTTP result body because it is
too long for the client, also adjust the Content-Length header.
2001-02-21 Tuomas Luttinen
* gw/wml_compiler.c (set_charset): The function uses now
charset_to_utf8 function to convert the WML document into the
UTF-8 charset before feeding it to the libxml parser.
* gwlib/charset.[ch]: Added the functions charset_to_utf8 and
charset_from_utf8. These are frontend for the libxml character set
converion funtions.
2001-02-20 Peter Grnholm
* userguide: Updated section "Installing Kannel from RPM packages"
2001-02-20 Richard Braakman
* userguide: Explained more about syslog-level.
2001-02-16 Richard Braakman
* gw/smsbox.c: Fix a potential buffer overflow in sms_split(),
by removing the partlist array and using List directly.
* gw/urltrans.c: Fix memory leak: destroy_onetrans also destroys
"header" and "footer".
* gw/urltrans.c: Warn if a service configures prefix or suffix
when they will not be used.
* userguide: Describe when prefix and suffix are used.
* userguide: Improve description of "omit-empty". (Suggested
by Gildas Perrot.)
2001-02-16 Richard Braakman
* gw/bb_smscconn.c, gw/urltrans.c: Deal with cfg_get_multi_group()
possibly being NULL.
* gw/bb_smscconn_p.h: Add #include "smscconn.h" so that it doesn't
depend on the caller having included that file already.
2001-02-15 Lars Wirzenius
* gw/smpp_pdu.def, gw/smsc_smpp.c: Implemented the enquire_link
PDU and the corresponding enquire_link_resp PDU. This should keep
Kannel connected to an SMPP SMS center even when the connection
is otherwise idle.
* test/drive_smpp.c: Cleaned up shutdown.
2001-02-15 Tuomas Luttinen
* gw/wml_compiler.c (set_charset): bug reported by Aymerick Jhanne
fixed so no more 2*encoding in the XML-header.
2001-02-15 Richard Braakman
* gw/smsc_at.c: Corrected timestamp calculation. mktime()
uses local time, and it got a GMT time. Converted to use
date_convert_universal() from gwlib/date.c instead.
(There is no function in the C library for this task.)
It probably still doesn't work for negative timezones,
I'll have to check the specs for that.
* gwlib/date.[ch]: Make date_convert_universal() a public
function.
2001-02-14 Lars Wirzenius
* gwlib/octstr.[ch]: Changed the octstr_create_urlcoded to be
similar in name and usage to octstr_url_decode.
* gw/bb_store.c, gw/smsc_fake.c, gw/urltrans.c: Changed the
places where the function is called.
2001-02-14 Lars Wirzenius
* gw/urltrans.c, doc/userguide/userguide.xml: Restored the
meaning of %a in sms-service, implemented and documented %b to
support binary data.
2001-02-14 Lars Wirzenius
* gw/smsbox.c, doc/userguide/userguide.xml: Implemented
X-Kannel-UDH header in responses to keyword fetches.
2001-02-13 Uoti Urpala
* gw/smsc.c: Fixed octstr_get_cstr(NULL) when username, password
or allow_ip wasn't specified in emi_ip smsc group. This bug
probably appeared when smsc.c was converted to use cfg.c.
2001-02-13 Richard Braakman
* gw/wml_definitions.h: Applied patch from Aymerick Jhanne
to correct encodings for "ordered true" and "ordered false".
2001-02-12 Kalle Marjola
* gw/bb_smscconn.c, gw/bb_boxc.c, gw/bearerbox.h: Modified so that
SMS messages from smsbox are directly put into corresponding SMS
centers, or if not able, either rejected (i.e. discarded right
now) or put to outgoing_sms queue which acts like delayed list
* gw/bb_smscconn_cb.h: added new callback, smscconn_connected,
which is called when status changes to ACTIVE, and makes bearerbox
trying to empty outgoing_sms queue
* gw/smsc_wrapper.c, gw/smsc_fake.c: modified to call that new
callback
2001-02-12 Lars Wirzenius
* Makefile.in: Moved -I. to before other -I options (before
@CFLAGS@) so that Kannel's config.h is found before any config.h
that might be a system header file.
2001-02-12 Kalle Marjola
* gw/bb_store.c: Ooops, forgot to add earlier. Anyway, now uses
straight octstr handling instead of using octstr_split and thus
does not need so much memory while unpacking the store-file
2001-02-12 Kalle Marjola
* gw/bb_boxc.c: removed heartbeat message kludge as it caused
other problems, had to think this more...
* gw/bb_http.c: removed debug information of HTTP query result
because it caused ankward output
* gw/bb_store.c: Added. Handles SMS store
* gw/msg-decl.h, gw/msg.h: added new 'ack' message type and new
fields to sms. Name of these can change later.
* gw/bb_boxc.c, gw/bb_smscconn.c, gw/bearerbox.c, gw/smsbox.c:
implemented first version of SMS storing/retrieval system.
Consumes lots of memory when starting up, so does not work
well with checking malloc, will fix that today.
* gw/*kannel.conf: added (commented-out) store-file row
2001-02-10 Uoti Urpala
* gw/smsbox.c: Fixed bugs in smsbox_req_sendota(), added 'from'
CGI variable to sendota requests.
* gwlib/cfg.def: Added missing 'speed' variable to otaconfig
group.
* doc/userguide/userguide.xml: Documented the added 'from'
variable. 'speed' was also missing from the documentation.
* gw/smsc_fake.c: Implemented SMSCCONN_FAILED_TEMPORARILY
(probably doesn't make much difference in practice).
* gwlib/octstr.c: Fixed memory leak in octstr_append_from_hex().
2001-02-08 Richard Braakman
* Applied Stipe Tolj's patch to cfg.def and userguide, to
fix OTA configuration parsing.
2001-02-07 Kalle Marjola
* gw/bb_boxc.c: kludged to use internal heartbeat to wakeup sender
from consume if other end closes the connection
* gw/bb_smscconn.c: modified failed routing access log output
* utils/accesslog_parser.pl: added failed routing to final output,
and change all keywords to lowercase
2001-02-07 Kalle Marjola
* utils/accesslog_parser.pl: added simple perl script to read
(SMS) access log and print statistics out of it, based on hours.
Uses the new format printed out by bb_smscconn.c
2001-02-07 Kalle Marjola
* gw/bearerbox.c: Bugfix. Fixed memory leak caused by access log /
new config
* doc/userguide/userguide.xml: made it clearer that sms-service is
selected by keyword and number of parameters
* gw/bb_smscconn.c: Bugfix: fixed access log to use Octstring return value
* gw/bb_smscconn.c: Compatibility breaker: modified access log
output
2001-02-07 Yann Muller
* gw/smsc_at.c: added support for Ericsson GSM modems (patch from
Chris Blown).
2001-02-06 Uoti Urpala
* gw/urltrans.c: Changed the %a URL parameter to mean the original
message as-is, to allow binary data. Previously consecutive
whitespace characters were changed into one space. Note that %r
was NOT changed, maybe it should work similarly?
2001-02-06 Kalle Marjola
* gw/bb_smscconn_cb.h: added new failed sending status,
SMSCCONN_FAILED_TEMPORARILY, which should be called if connection
to SMS center is lost temporarily
* gw/bb_smscconn.c: added handling for new status
* gw/smscconn_p.h: added comments of the new status
* gw/smsc_wrapper.c: added that when reconnect is started, message
queue is emptied from messages with status
SMSCCONN_FAILED_TEMPORARILY
2001-02-06 Peter Grnholm
* utils/kannel-stable-rh6x.spec: Added rpm spec file for Kannel
stable releases.
* utils/kannel-stable-rh7.spec: Added rpm spec file for Kannel
stable releases.
2001-02-06 Uoti Urpala
* gw/smsbox.c: Rewrote message-splitting functions because they
had lots and lots of bugs. Basically they didn't work if
split-chars, split-suffix or concatenation was defined.
2001-02-05 Richard Braakman
* gwlib/octstr.c: Fixed off-by-one error in octstr_case_search(),
reported by Vjacheslav Chekushin.
2001-02-04 Richard Braakman
* wmlscript/wsasm.c: Avoid generating 0-length functions,
because not all clients can handle them.
* gw/wap-appl.c: If the response body does not fit in the
client SDU size, generate status code 502 ("Bad Gateway")
instead of 413 ("Request Entity Too Large"). 413 is definitely
the wrong code because it refers to the request, not the
response. 502 means the gateway received an invalid response
from the server, which is pretty close.
Also, do not touch the status code at all if it already indicates
an error. The upstream error is more interesting to the user
than knowing that the error page didn't fit.
* gwlib/http.[ch]: Add http_status_class() function to
distinguish success codes (2xx) from error codes.
2001-02-02 Tuomas Luttinen
* test/decompile.[ch]: Applied the patch by Neil Hunter that
implements the codepage switch, changes the indent size to a #define
and adds basic support for different DTDs.
* gw/utf8map_iso8859-7.h, gw/utf8map_win1251.h, gw/utf8map_win1257.h,
gw/utf8map_koi8r.h, gw/utf8map_win1253.h: removed as obsolete.
* gw/wml_compiler.c: Patch by Vjacheslav Chekushin applied. The
patch makes the libxml aware of some aliases for different
character_sets, so these can be used in the WML content with the
libxml.
Some other modifications due modifications in the wml_definitions.h.
* gw/wml_definitions.h: Patch by Vjacheslav Chekushin applied. The
patch removes the use of the utf8map in the character_sets[].
Also utf8map removed from the character_sets[].
2001-02-02 Tuomas Luttinen
* gw/wml_compiler.c (string_table_collect_strings): Removed the
if (strlen(node->content) > WBXML_STRING_TABLE_MIN) -line that
won't work with XML_USE_BUFFER_CONTENT.
2001-02-02 Richard Braakman
* Added gwmem_type() function that returns the name of the
malloc wrapper used.
* gw/shared.c: Report gwmem_type in the version string.
2001-02-01 Richard Braakman
* Updated doc/release.txt to better reflect actual procedure.
Only covers development releases for now.
gateway-1.4.3/doc/ChangeLog-1.2.1 0000644 0001750 0001750 00000061524 10203150323 015167 0 ustar soren soren 2002-10-19 Stipe Tolj
* wap/wsp_headers.c: roll-back to previous revision. We have to resolve
this issue more carefully.
2002-10-17 Stipe Tolj
* gw/smsc/smsc_smasi.c: added enquire_link facility to sm/asi protocol.
Can be configured via 'enquire-link-interval' directive.
2002-10-17 Stipe Tolj
* gw/smsc/smsc_smpp.c: fixed a typo in DLR error handling.
Thanks to Alexander Malysh for spotting this.
[Msg-ID: <200210161940.36328.a.malysh@centrium.de>]
2002-10-16 Stipe Tolj
* test/test_octstr_immutable.c: minor change to make dumping of arguments
possible to.
2002-10-16 Stipe Tolj
* wap/wsp_headers.c: fixed a bug in WSP header packing that breaked MMS
notification sending via PPG.
2002-10-16 Stipe Tolj
* doc/userguide/userguide.xml: added documentation to SMPP's directives
[source|dest]-addr-[ton|npi] and source-addr-autodetect.
* gw/smsc/smsc_smpp.c: changed DLR msg_id behaviour. SMPP spec says msg
ids should be C string, this is default now. Via msg-id-type users
may configure for smpp connections that use dec and hex values or mixes
of those.
* gwlib/cfg.def: added 'source-addr-autodetect' to smsc group for
auto-detecting source addr in smpp module.
2002-10-16 Stipe Tolj
* gw/bb_smscconn.c: fixed a bug in http admin /status page routine if smsc
groups did not have any smsc-id declared.
Patch has been submited by Rene Kluwen
[Msg-ID: <006501c2708f$52284400$1401a8c0@helena>]
2002-10-16 Stipe Tolj
* gw/smsc/smsc_smpp.c: roll-back to previous revision. Veto'ed Andreas
commit because it took out the new msg-id-type feature, which is required
by certain SMSC vendors.
2002-10-16 Andreas Fink
* gwlib/http.c: fixed http basic authentication for DLRs
a dlrurl containing username and password was crashing kannel before
because http headers where not initialized. also potentially a problem
in other places.
2002-10-15 Stipe Tolj
* gwlib/utils.c: fixed a bug in does_prefix_match(), when a number gets
not recognized if it has the same length as in prefix list. Now
prefix = number does get matched.
2002-10-15 Andreas Fink
* gw/dlr.c gw/smsc/smsc_smpp.c: fixed DLR reports if message ID was hex or alpha
2002-10-15 Stipe Tolj
* gw/smsc/smsc_smasi.c: added enquire_link feature to pass a newline
throught this connection to keep the TCP session up.
2002-09-23 Oded Arbel
* gwlib/octstr.c: Fixed bug in octstr_insert_char(), patch by
Rene Kluwen
[Msg-Id: <75184712412.20020923031314@chimit.nl>]
2002-09-23 Andreas Fink
* gwlib/octstr.c: fixed memory leak in octstr_url_encode
2002-09-19 Oded Arbel
* gw/smsc/smsc_at.c: Fixed a bug in at_receive(), reported by Rene Kluwen
[Msg-ID: <200209191406.g8JE6L8H017962@ns.nesscis.com>]
2002-09-18 Oded Arbel
* gw/wap_push_ppg.c: Fixed a bug in get_mime_boundary that would cause
it to get into an endless loop if the boundary was not ; terminated.
changed the HTML entity name of a double quote from &qt; to "
and added ';' at the end of HTML entity, fixed endless loop bug
in escape_fragment().
2002-09-09 Stipe Tolj
* config.h.in, configure[.in], gwlib/cfg.c: veto against #define WIN32.
This shoould be only used for Win32 native support, *not* for Cygwin
support.
2002-09-08 Bruno Rodrigues
* doc/userguide/userguide.xml: fix
2002-09-06 Bruno Rodrigues
* gwlib/cfg.c, doc/userguide/userguide.xml: added directory include to
configuration. If "include" argument is a directory, include the files
* configure.in, config.h.in: Added #define WIN32 awareness
* doc/userguide/userguide.xml: "un-drafted" post-xml
* utils/build-cygwin-package: added first alpha version to a script to
build some package for windows. Now, it creates a zip file with the
executables, docs (if generated) and example configuration files
2002-09-06 Stipe Tolj
* gw/smsc/smsc_smpp.c: fixed a problem with the range of sequence_number.
Reported by Angel.
[Msg-ID: ]
2002-09-06 Stipe Tolj
* gw/bb_boxc.c, gw/bearerbox.c: made boxid++ thead-safe via mutex
* docs/userguide/userguide.xml: documented the smsc specific
'unified-prefix' directive for number normalization
* gw/bb_smscconn.c, gw/smscconn.c, gw/smscconn_p.h: added 'unified-prefix'
function on a smsc basis to set number normalization rules.
* gwlib/cfg.def: added 'unified-prefix' to multi-group 'smsc'.
2002-09-06 Andreas Fink
* gw/dlr.c: fixed a crash when migrating from MySQL database
without source field to one which has.
2002-09-06 Andreas Fink
* gw/dlr.c: fixed Stipe's modifications so it at least compiles!
2002-09-06 Stipe Tolj
* gw/dlr.c: fixing dlr_add_() routines for the new DLR handling way.
Thanks to Oded for reporting this.
* gw/smsc/smsc_smpp.c, gw/smsc/smsc_at2.c: another fixes for the new DLR
handling way. And again, reported by Oded :)
2002-09-06 Andreas Fink
* gw/dlr.c: added Oded's patch to fix a missing parameter in mysql DLR.
2002-09-05 Stipe Tolj
* gwlib/utils.[ch], gw/urltrans.c, gw/smscconn.c: moved the identical
routine does_prefix_match() from urltrans.c and smsccon.c to the
higher abtraction layer to utils.c and made it publically available.
2002-09-05 Stipe Tolj
* gw/dlr.c: fixed a bug caused by a typo
* gwlib/http.c, gwlib/parse.c: fixed minor compiler warnings
2002-09-04 Stipe Tolj
* gw/dlr.[ch], gw/urltrans.c: added a 'source' field to the DLR storage
space, hence modified the dlr_add() call parameters.
Re-organized how the DLR msg structs are transfered to smsbox and the
msg->sms.dlr_url is now used to get the DLR URL. This is more clean
and makes DLR proxying accross different SMSC modules posible.
* gwlib/cfg.def: added 'field-source' for the mysql dlr definition
* gw/smsc/smsc_*.c: added source parameter to call dlr_add() and changed
msg->sms.msgdata handling after dlr_find()
* gw/smsc/smpp_pdu.h: added submit_sm and deliver_sm esm_class defines
2002-09-04 Aarno Syv\212nen
* STATUS: updated
* TODO: typo fix
* checks/check_ppg.sh: typo fix
* gw/bb_boxc.c: Reformatted. Store wap push messages to the store file.
* gw/pushkannel.conf: Added country-prefix to the example file.
* gw/wap_push_ota.c: Minor formatting change.
* gw/wap_push_ppg_pap_compiler.c: Ditto
* gw/wap_push_mime.c: Better public function comment
* gw/wap_push_ppg.c: Reformatted. Handling missing denied and allowed
lists. Remove X-WAP-Application-Id header, when user agent is wml.ua.
If there is none, assume wml.ua. Removed push.sia requirement, when push
is confirmed. Use 'any' as default bearer and network. Do not add Content-
Type header to responses. Use xml escapes when sending message fragment
to pi.
* gw/wap_push_ppg_pushuser.c: Reformatted. Use country-prefix. Handle
missing allowed and denied lists. Do not add Content-Length to the
responses. Edited function compare_octstr_sequence.
* gwlib/cfg.def: Added country prefix.
* gwlib/gwthread_pthread.c: Reformatted. Dummu function for older MacOSXs
returns a value.
* gwlib/http.[ch]: Added function http_header_value.
* gwlib/octstr.[ch]: Added function octstr_insert_char. Memory leak wrapper
around function octstr_format_valist.
* gwlib/parse.[ch]: Added function parse_get_rest.
* test/test_ppg.c: Removed content type sia. Use mms.ua as X-WAP-Applica-
tion-Id value. Reformatted. Do not add Content-Length header. Use HTTP
POST in test_ppg requests.
* wap/wsp_strings.def: Added new content types and headers from newer wap
specs.
2002-09-04 Stipe Tolj
* gw/smsc/smasi_pdu.c, test/test_cfg.c: fixed compiler warnings
2002-09-03 Stipe Tolj
* gw/smsc/smpp_pdu.c: fixed a bug in copy_until_nul() which caused to return
octstr "" when the null-terminated string contained "\0". The return value
in such a case should be NULL.
2002-09-03 Stipe Tolj
* doc/userguide/userguide.xml: documentation for the new 'msg-id-type'
directive for the SMPP module
* gw/smsc/smsc_smpp.c, gwlib/cfg.def: adding the 'msg-id-type' directive
to indicate in which number base the SMSC is returning msg ids.
Patch provided by Nisan Bloch .
[Msg-ID: <5.1.0.14.0.20020819203925.020675c0@amagoblin.ialien.co.za>]
2002-09-02 Stipe Tolj
* gw/shared.[ch]: added deliver_to_bearerbox() which is identical to write_xxx
but returns an error code which can be used for errror handling.
* gwlib/cfg.[ch]: switched from static void dump_group() to void grp_dump()
to make this function publically available and usable in the code.
2002-08-26 Stipe Tolj
* gw/bb_store.c: obey if we log in localtime for the store-status
2002-08-26 Stipe Tolj
* test/test_cfg.c: added error code return for int main() to indicate if a
configuration syntax was ok or not. This can be used in control shell
scripts to check Kannel's configuration files.
2002-08-23 Stipe Tolj
* gwlib/http.c: fixed HTTP persistent connection misbehaviour in
http_send_reply() which caused to do keep-alives, even while the client
requested to close the connection.
2002-08-23 Stipe Tolj
* gw/smsc/smsc_at2.c, gwlib/http.c: fixed a minor compiler warnings
* gw/smsc/smsc_smpp.c: fixed a type in handle_pdu(), reported by
Vibhu Mohindra
[Msg-ID: <20020822214514.GA4279@lfs.localdomain>]
2002-08-22 Stipe Tolj
* wap/wap_events.def, wap/wtp.c: added a RcvResult event and a coresponding
unpack_result() function. This is necessary for an upcoming wap proxy.
2002-08-22 Stipe Tolj
* doc/userguide/userguide.xml, gw/smsc/smsc_at.[ch], gw/sms.h:
Oded's patch for full DLR support in AT2 module. Some further
improvements and fixes included.
[Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296F5A@exchange.m-wise.com>]
2002-08-20 Stipe Tolj
* gwlib/http.[ch]: added HEAD method support for HTTP client module
functions, this modifies the http_start_request() prototype.
* gw/numhash.c, test/test_smsc.c: changed calls to http_get_real()
* gw/smsbox.c: added method to remember_receiver() and get_receiver() and
changed calls to http_start_request()
* gw/wap-app.c, gw/smsc/smsc_http.c, gwlib/xmlrpc.c, test/test_ppg.c:
changed calls to http_start_request()
* test/test_http.c: added -m option so select HTTP method type for request
and changed calls to http_start_request()
2002-08-19 Stipe Tolj
* wap/wtp_pdu.def: changed the TPI documentation string to make them more
specification conform.
2002-08-19 Stipe Tolj
* gw/smsc/smsc_smpp.c: fixed a bit calculus typo, reported by Nisan.
[Msg-ID: <5.1.0.14.0.20020819154851.02066060@amagoblin.ialien.co.za>]
2002-08-19 Stipe Tolj
* gw/smsc/smasi_pdu.c: fixed a parsing bug in decode_type() and switched
some error levels from error to warning for the sake of the logs.
2002-08-15 Stipe Tolj
* doc/userguide/userguide.xml: added new SMSC type section for the SM/ASI
protocol.
* gw/smsc/smasi_pdu.[chdef], gw/smsc/smsc_smasi.c, gw/smscconn.c,
gw/smscconn_p.h: added the new 'smasi' SMSC type for connecting to
SM/ASI protocol SMSC, like the CriticalPath InVoke SMS Center.
2002-08-15 Stipe Tolj
* gw/bb_smscconn.c: removing debug line from previous testing and
commented out lines and added 're-connecting' state to smsc2_status().
* gw/smsc/smsc_smpp.c: fixed a bug with possible segfault when acessing the
smpp->msgs_to_send in queued_cb() while the connection has been shutdown
and the status page queueries all available connections.
2002-08-13 Harrie Hazewinkel
* Changed the '' into '(null)' since the former is
to close to XML and may cause confusion.
2002-08-13 Stipe Tolj
* test/test_http_server.c: allow to use multi-threaded HTTP server tests
2002-08-12 Stipe Tolj
* gw/smsc/smpp_pdu.c: fixing a compiler warning
* gwlib/octstr.[ch].debug: added missing octstr_recode() and _read_pip()
functions in the debug version of the octstr module
2002-08-11 Stipe Tolj
* gw/smsc/smpp_pdu.[chdef], gw/smsc/smsc_smpp.c: rollback to previous
revision and adding a silent fix to SMPP PDU elements that are too long.
* Makefile.in: fixing missing dependency generation in file .depend for
all modules in the 'new' gw/smsc sub-directory. This has caused to keep
make quite, even while source files changed in gw/smsc.
2002-08-11 Harrie Hazewinkel
* Moved more smsc related code into gw/smsc/
gw/smsc.h -> gw/smsc/smsc.h
gw/smsc_p.h -> gw/smsc/smsc_p.h
* gwlib.octstr.c: graceful handling of the Octstr* when it is
NULL, instead of panicing.
Oded Arbel
[Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296EEF@exchange.m-wise.com>]
* Converted all doc/ChangeLog-* file to have a UNIX line ending and
not the '^M'.
* gw/smsc/smsc_smpp.c, gw/smsc/smpp_pdu.h, gw/smsc/smpp_pdu.def:
Make sure that the address length going into the PDU is not longer
then the maximum length. If the address is longer it causes a panic.
Oded Arbel
[Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296EEF@exchange.m-wise.com>]
2002-08-10 Stipe Tolj
* gwlib/list.c: fixed a mutex_destroy() problem, because list is still
locked while mutex is destroyed.
2002-08-09 Harrie Hazewinkel
* Moving the smsc code into a subdiretory gw/smsc.
files moved (into gw/smsc):
emimsg.c emimsg.h smpp_pdu.c smpp_pdu.def smpp_pdu.h
files changed: test/drive_smpp.c test/test_smsc.c
2002-08-08 Stipe Tolj
* gw/smsc/smsc_http.c: fixed the "failed" logging to access.log, which was
caused because the relayed smsbox instance send HTTP_ACCEPT and the
module did only like HTTP_OK.
* ChangeLog: reorganized the huge ChangeLog to version specific chunks
into doc/. Only changes since the last stable release are inside the
current ChangeLog in the top level directory from now on.
2002-08-08 Harrie Hazewinkel
* Moving the smsc code into a subdiretory gw/smsc.
Only the smsc.h, smsc_p.h smscconn.h and smscconn.c are
as API still in the gw directory.
files moved (into gw/smsc):
smsc_at2.h, smsc_cimd2.c, smsc_fake.c, smsc_sema.c, smsc.c,
smsc_sema.h, smsc_cgw.c, smsc_emi.c, smsc_http.c, smsc_at.c,
smsc_smpp.c, smsc_cimd.c, smsc_emi2.c, smsc_ois.c, smsc_at2.c,
smsc_wrapper.c
files changed: Makefile.in gw/smscconn.c, gw/smscconn_p.h
2002-08-08 Harrie Hazewinkel
* configure.in: Be a little less strict for the '--enable-warnings'
* gwlib/conn.h: fixed 3 warnings.
2002-08-08 Stipe Tolj
* gw/smsc_http.c: typo fix.
* gw/wap-appl.c: added HTTP HEAD method for WSP->HTTP requests
2002-08-07 Stipe Tolj
* gw/bb_store.c: fixed a segfault bug in store_status()
2002-08-07 Stipe Tolj
* gw/bb_http.c, gw/bearerbox.[ch] : renaming start operation to 'restart'
to indicate that this is used after bearerbox has started and individual
smsc have been shutdown previously.
* gw/bb_smscconn.c: fixed serious problems in /stop-smsc, /start-smsc
admin commands and /status page retrieval
* gw/smsc_emi2.c, gw/smsc_fake.c: fixed a segmenation fault bug, which was
caused by /status page lookup when a specific conn was already shutdown
2002-08-07 Harrie Hazewinkel