1/*
2    Copyright 2004, Broadcom Corporation
3    All Rights Reserved.
4
5    THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
6    KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
7    SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
8    FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
9*/
10
11#include <stdarg.h>
12
13#include "upnp_dbg.h"
14#include "upnp_osl.h"
15#include "upnp.h"
16
17extern char *getsvcval(PService psvc, int i);
18extern void soap_response(UFILE*, const char *, const char *, const char *, pvar_entry_t, int);
19
20PService init_service(PServiceTemplate svctmpl, PDevice pdev)
21{
22    PService psvc;
23    PFSVCINIT func;
24    int i, table_size;
25
26    UPNP_TRACE(("Initializing service \"%s\".\r\n", svctmpl->name));
27
28    if (svctmpl->schema == NULL)
29	svctmpl->schema = "schemas-upnp-org";
30
31    psvc = (PService) malloc(sizeof(Service));
32    memset(psvc, 0, sizeof(Service));
33
34    // store pointers to the template and the device into the service.
35    psvc->template = svctmpl;
36    psvc->device = pdev;
37    psvc->instance = ++svctmpl->count;
38
39    // allocate and initialize the service's state variables.
40    table_size = svctmpl->nvariables * sizeof(StateVar);
41    psvc->vars = (StateVar *) malloc(table_size);
42    memset(psvc->vars, 0, table_size);
43
44    for (i = 0; i < svctmpl->nvariables; i++) {
45	strcpy(psvc->vars[i].value, svctmpl->variables[i].value);
46	psvc->vars[i].flags = svctmpl->variables[i].flags;
47	assert((psvc->vars[i].flags & VAR_CHANGED) == 0);
48    }
49
50    // call the service's intialization function, if defined.
51    if ((func = svctmpl->svcinit) != NULL) {
52	(*func)(psvc, SERVICE_CREATE);
53    }
54
55    return psvc;
56}
57
58void destroy_service(PService psvc)
59{
60    PFSVCINIT func;
61
62    UPNP_TRACE(("Destroying service \"%s\".\r\n", psvc->template->name));
63
64    // call the service's intialization function, if defined.
65    if ((func = psvc->template->svcinit) != NULL) {
66	(*func)(psvc, SERVICE_DESTROY);
67    }
68
69    free(psvc->vars);
70    free(psvc);
71}
72
73
74void mark_changed(PService psvc, int varindex)
75{
76    assert(varindex >= 0 && varindex <= psvc->template->nvariables);
77
78    psvc->vars[varindex].flags |= VAR_CHANGED;
79    psvc->flags |= VAR_CHANGED;
80}
81
82
83/* Print an XML device description for a device and all its subdevices.
84   We used to just print the static XML device description from a file, but now that the
85   IGD is more dynamic and can adjust to different gateway configurations,
86   we must dynamically generate the XML.
87 */
88void service_xml(PService psvc, UFILE *up)
89{
90    const char *type2str(vartype_t type);
91    PFSVCXML func;
92    PVarTemplate pv;
93    PAction *ac;
94    PParam pa;
95    char *tstr;
96
97    uprintf(up,
98	    "<?xml version=\"1.0\"?>\r\n"
99	    "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\r\n"
100	    "  <specVersion>\r\n"
101	    "    <major>1</major>\r\n"
102	    "    <minor>0</minor>\r\n"
103	    "  </specVersion>\r\n");
104
105    // call the service's xml function, if defined.
106    if ((func = psvc->template->svcxml) != NULL) {
107	(*func)(psvc, up);
108    }
109
110    uprintf(up, "<actionList>\r\n");
111    if (psvc->template->actions) {
112	for (ac = psvc->template->actions; *ac; ac++) {
113	    uprintf(up, "<action>\r\n");
114	    uprintf(up, "<name>%s</name>\r\n", (*ac)->name);
115
116	    /* don't print any <argumentList> if there are no args. */
117	    if ((pa = (*ac)->params) && pa->name) {
118		uprintf(up, "<argumentList>\r\n");
119		while (pa->name) {
120		    uprintf(up, "<argument>\r\n");
121		    uprintf(up, "<name>%s</name>\r\n", pa->name);
122		    uprintf(up, "<relatedStateVariable>%s</relatedStateVariable>\r\n",
123			    psvc->template->variables[pa->related].name);
124		    uprintf(up, "<direction>%s</direction>\r\n",
125			    (pa->flags == VAR_OUT ? "out" : "in"));
126		    uprintf(up, "</argument>\r\n");
127
128		    pa++;
129		}
130		uprintf(up, "</argumentList>\r\n");
131	    }
132	    uprintf(up, "</action>\r\n");
133	}
134    }
135    uprintf(up, "</actionList>\r\n");
136
137    uprintf(up, "<serviceStateTable>\r\n");
138    for (pv = psvc->template->variables; pv->name; pv++) {
139	uprintf(up, "<stateVariable sendEvents=\"%s\">\r\n",
140		(pv->flags & VAR_EVENTED ? "yes" : "no"));
141	uprintf(up, "  <name>%s</name>\r\n", pv->name);
142	tstr = type2str(pv->flags&VAR_TYPE_MASK);
143	if (tstr == NULL) {
144	    UPNP_ERROR(("unknown type - %s \"%s\"\r\n",
145			psvc->template->name, pv->name));
146	} else {
147	    uprintf(up, "  <dataType>%s</dataType>\r\n", tstr);
148	}
149
150	if ((pv->flags & VAR_LIST) && pv->allowed.list ) {
151	    char ** avl;
152	    uprintf(up, "    <allowedValueList>\r\n");
153	    for (avl = pv->allowed.list; *avl; avl++) {
154		uprintf(up, "      <allowedValue>%s</allowedValue>\r\n", *avl);
155	    }
156	    uprintf(up, "    </allowedValueList>\r\n");
157	} else if ((pv->flags & VAR_RANGE) && pv->allowed.range ) {
158	    PallowedValueRange avr =  pv->allowed.range;
159	    uprintf(up, "    <allowedValueRange>\r\n");
160	    uprintf(up, "    <minimum>%s</minimum>\r\n", avr->minimum);
161	    uprintf(up, "    <maximum>%s</maximum>\r\n", avr->minimum);
162	    uprintf(up, "    <step>%s</step>\r\n", avr->step);
163	    uprintf(up, "    </allowedValueRange>\r\n");
164	}
165
166	uprintf(up, "</stateVariable>\r\n");
167    }
168    uprintf(up, "</serviceStateTable>\r\n");
169
170
171    uprintf(up, "</scpd>\r\n");
172}
173
174
175const char *type2str(vartype_t type)
176{
177    char *str;
178
179    switch (type) {
180    case VAR_UBYTE:
181	str = "ui1";
182	break;
183    case VAR_USHORT:
184	str = "ui2";
185	break;
186    case VAR_ULONG:
187	str = "ui4";
188	break;
189    case VAR_BYTE:
190	str = "i1";
191	break;
192    case VAR_SHORT:
193	str = "i2";
194	break;
195    case VAR_LONG:
196	str = "i4";
197	break;
198    case VAR_STRING:
199	str = "string";
200	break;
201    case VAR_BOOL:
202	str = "boolean";
203	break;
204    default:
205	str = NULL;
206    }
207    return str;
208}
209
210
211
212// NOT IMPLEMENTED
213int NotImplemented(UFILE *up, PService psvc, PAction ac, pvar_entry_t args, int nargs)
214{
215    UPNP_ERROR(("Action \"%s\" not implemented, svc \"%s\"\r\n", ac->name, psvc->template->name));
216
217    soap_error( up, SOAP_INVALID_ACTION );
218
219    /* indicate that we have already handled the response.
220       (see the handling of return code from 'func' in invoke(). */
221    return FALSE;
222}
223
224
225
226/* The default action is to reflect the contents of the related variables to all OUT parameters.
227   That is, if an action has an OUT param, return the value of the <relatedVariable> for that param.
228   Do the same for any other out params.
229
230   The value of related variables is obtained by calling getsvcval().
231*/
232int DefaultAction(UFILE *up, PService psvc, PAction ac,
233		  pvar_entry_t args, int nargs)
234{
235    PParam pa;
236
237    for (pa = ac->params; pa->name; pa++) {
238	if (pa->flags & VAR_OUT) {
239	    pa->value = getsvcval(psvc, pa->related);
240	}
241    }
242
243    return TRUE;
244}
245