1/* $Id: upnpcommands.c,v 1.44 2014/06/10 09:44:07 nanard Exp $ */
2/* Project : miniupnp
3 * Author : Thomas Bernard
4 * Copyright (c) 2005-2012 Thomas Bernard
5 * This software is subject to the conditions detailed in the
6 * LICENCE file provided in this distribution.
7 * */
8#include <stdlib.h>
9#include <stdio.h>
10#include <string.h>
11#include "upnpcommands.h"
12#include "miniupnpc.h"
13#include "portlistingparse.h"
14
15static UNSIGNED_INTEGER
16my_atoui(const char * s)
17{
18	return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0;
19}
20
21/*
22 * */
23MINIUPNP_LIBSPEC UNSIGNED_INTEGER
24UPNP_GetTotalBytesSent(const char * controlURL,
25					const char * servicetype)
26{
27	struct NameValueParserData pdata;
28	char * buffer;
29	int bufsize;
30	unsigned int r = 0;
31	char * p;
32	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
33	                                "GetTotalBytesSent", 0, &bufsize))) {
34		return UPNPCOMMAND_HTTP_ERROR;
35	}
36	ParseNameValue(buffer, bufsize, &pdata);
37	/*DisplayNameValueList(buffer, bufsize);*/
38	free(buffer); buffer = NULL;
39	p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent");
40	r = my_atoui(p);
41	ClearNameValueList(&pdata);
42	return r;
43}
44
45/*
46 * */
47MINIUPNP_LIBSPEC UNSIGNED_INTEGER
48UPNP_GetTotalBytesReceived(const char * controlURL,
49						const char * servicetype)
50{
51	struct NameValueParserData pdata;
52	char * buffer;
53	int bufsize;
54	unsigned int r = 0;
55	char * p;
56	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
57	                                "GetTotalBytesReceived", 0, &bufsize))) {
58		return UPNPCOMMAND_HTTP_ERROR;
59	}
60	ParseNameValue(buffer, bufsize, &pdata);
61	/*DisplayNameValueList(buffer, bufsize);*/
62	free(buffer); buffer = NULL;
63	p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived");
64	r = my_atoui(p);
65	ClearNameValueList(&pdata);
66	return r;
67}
68
69/*
70 * */
71MINIUPNP_LIBSPEC UNSIGNED_INTEGER
72UPNP_GetTotalPacketsSent(const char * controlURL,
73						const char * servicetype)
74{
75	struct NameValueParserData pdata;
76	char * buffer;
77	int bufsize;
78	unsigned int r = 0;
79	char * p;
80	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
81	                                "GetTotalPacketsSent", 0, &bufsize))) {
82		return UPNPCOMMAND_HTTP_ERROR;
83	}
84	ParseNameValue(buffer, bufsize, &pdata);
85	/*DisplayNameValueList(buffer, bufsize);*/
86	free(buffer); buffer = NULL;
87	p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent");
88	r = my_atoui(p);
89	ClearNameValueList(&pdata);
90	return r;
91}
92
93/*
94 * */
95MINIUPNP_LIBSPEC UNSIGNED_INTEGER
96UPNP_GetTotalPacketsReceived(const char * controlURL,
97						const char * servicetype)
98{
99	struct NameValueParserData pdata;
100	char * buffer;
101	int bufsize;
102	unsigned int r = 0;
103	char * p;
104	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
105	                                "GetTotalPacketsReceived", 0, &bufsize))) {
106		return UPNPCOMMAND_HTTP_ERROR;
107	}
108	ParseNameValue(buffer, bufsize, &pdata);
109	/*DisplayNameValueList(buffer, bufsize);*/
110	free(buffer); buffer = NULL;
111	p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived");
112	r = my_atoui(p);
113	ClearNameValueList(&pdata);
114	return r;
115}
116
117/* UPNP_GetStatusInfo() call the corresponding UPNP method
118 * returns the current status and uptime */
119MINIUPNP_LIBSPEC int
120UPNP_GetStatusInfo(const char * controlURL,
121				const char * servicetype,
122				char * status,
123				unsigned int * uptime,
124				char * lastconnerror)
125{
126	struct NameValueParserData pdata;
127	char * buffer;
128	int bufsize;
129	char * p;
130	char * up;
131	char * err;
132	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
133
134	if(!status && !uptime)
135		return UPNPCOMMAND_INVALID_ARGS;
136
137	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
138	                                "GetStatusInfo", 0, &bufsize))) {
139		return UPNPCOMMAND_HTTP_ERROR;
140	}
141	ParseNameValue(buffer, bufsize, &pdata);
142	/*DisplayNameValueList(buffer, bufsize);*/
143	free(buffer); buffer = NULL;
144	up = GetValueFromNameValueList(&pdata, "NewUptime");
145	p = GetValueFromNameValueList(&pdata, "NewConnectionStatus");
146	err = GetValueFromNameValueList(&pdata, "NewLastConnectionError");
147	if(p && up)
148	  ret = UPNPCOMMAND_SUCCESS;
149
150	if(status) {
151		if(p){
152			strncpy(status, p, 64 );
153			status[63] = '\0';
154		}else
155			status[0]= '\0';
156	}
157
158	if(uptime) {
159		if(up)
160			sscanf(up,"%u",uptime);
161		else
162			uptime = 0;
163	}
164
165	if(lastconnerror) {
166		if(err) {
167			strncpy(lastconnerror, err, 64 );
168			lastconnerror[63] = '\0';
169		} else
170			lastconnerror[0] = '\0';
171	}
172
173	p = GetValueFromNameValueList(&pdata, "errorCode");
174	if(p) {
175		ret = UPNPCOMMAND_UNKNOWN_ERROR;
176		sscanf(p, "%d", &ret);
177	}
178	ClearNameValueList(&pdata);
179	return ret;
180}
181
182/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method
183 * returns the connection type */
184MINIUPNP_LIBSPEC int
185UPNP_GetConnectionTypeInfo(const char * controlURL,
186                           const char * servicetype,
187                           char * connectionType)
188{
189	struct NameValueParserData pdata;
190	char * buffer;
191	int bufsize;
192	char * p;
193	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
194
195printf("0\n");
196	if(!connectionType)
197		return UPNPCOMMAND_INVALID_ARGS;
198printf("1\n");
199
200	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
201	                                "GetConnectionTypeInfo", 0, &bufsize))) {
202		return UPNPCOMMAND_HTTP_ERROR;
203	}
204printf("2\n");
205	ParseNameValue(buffer, bufsize, &pdata);
206	free(buffer); buffer = NULL;
207	p = GetValueFromNameValueList(&pdata, "NewConnectionType");
208	/*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/
209	/* PossibleConnectionTypes will have several values.... */
210	if(p) {
211		strncpy(connectionType, p, 64 );
212		connectionType[63] = '\0';
213		ret = UPNPCOMMAND_SUCCESS;
214	} else
215		connectionType[0] = '\0';
216	p = GetValueFromNameValueList(&pdata, "errorCode");
217	if(p) {
218		ret = UPNPCOMMAND_UNKNOWN_ERROR;
219		sscanf(p, "%d", &ret);
220	}
221	ClearNameValueList(&pdata);
222printf("3\n");
223	return ret;
224}
225
226/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method.
227 * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth.
228 * One of the values can be null
229 * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only
230 * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */
231MINIUPNP_LIBSPEC int
232UPNP_GetLinkLayerMaxBitRates(const char * controlURL,
233                             const char * servicetype,
234                             unsigned int * bitrateDown,
235                             unsigned int * bitrateUp)
236{
237	struct NameValueParserData pdata;
238	char * buffer;
239	int bufsize;
240	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
241	char * down;
242	char * up;
243	char * p;
244
245	if(!bitrateDown && !bitrateUp)
246		return UPNPCOMMAND_INVALID_ARGS;
247
248	/* shouldn't we use GetCommonLinkProperties ? */
249	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
250	                                "GetCommonLinkProperties", 0, &bufsize))) {
251	                              /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/
252		return UPNPCOMMAND_HTTP_ERROR;
253	}
254	/*DisplayNameValueList(buffer, bufsize);*/
255	ParseNameValue(buffer, bufsize, &pdata);
256	free(buffer); buffer = NULL;
257	/*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/
258	/*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/
259	down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate");
260	up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate");
261	/*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/
262	/*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/
263	if(down && up)
264		ret = UPNPCOMMAND_SUCCESS;
265
266	if(bitrateDown) {
267		if(down)
268			sscanf(down,"%u",bitrateDown);
269		else
270			*bitrateDown = 0;
271	}
272
273	if(bitrateUp) {
274		if(up)
275			sscanf(up,"%u",bitrateUp);
276		else
277			*bitrateUp = 0;
278	}
279	p = GetValueFromNameValueList(&pdata, "errorCode");
280	if(p) {
281		ret = UPNPCOMMAND_UNKNOWN_ERROR;
282		sscanf(p, "%d", &ret);
283	}
284	ClearNameValueList(&pdata);
285	return ret;
286}
287
288
289/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
290 * if the third arg is not null the value is copied to it.
291 * at least 16 bytes must be available
292 *
293 * Return values :
294 * 0 : SUCCESS
295 * NON ZERO : ERROR Either an UPnP error code or an unknown error.
296 *
297 * 402 Invalid Args - See UPnP Device Architecture section on Control.
298 * 501 Action Failed - See UPnP Device Architecture section on Control.
299 */
300MINIUPNP_LIBSPEC int
301UPNP_GetExternalIPAddress(const char * controlURL,
302                          const char * servicetype,
303                          char * extIpAdd)
304{
305	struct NameValueParserData pdata;
306	char * buffer;
307	int bufsize;
308	char * p;
309	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
310
311	if(!extIpAdd || !controlURL || !servicetype)
312		return UPNPCOMMAND_INVALID_ARGS;
313
314	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
315	                                "GetExternalIPAddress", 0, &bufsize))) {
316		return UPNPCOMMAND_HTTP_ERROR;
317	}
318	/*DisplayNameValueList(buffer, bufsize);*/
319	ParseNameValue(buffer, bufsize, &pdata);
320	free(buffer); buffer = NULL;
321	/*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/
322	p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress");
323	if(p) {
324		strncpy(extIpAdd, p, 16 );
325		extIpAdd[15] = '\0';
326		ret = UPNPCOMMAND_SUCCESS;
327	} else
328		extIpAdd[0] = '\0';
329
330	p = GetValueFromNameValueList(&pdata, "errorCode");
331	if(p) {
332		ret = UPNPCOMMAND_UNKNOWN_ERROR;
333		sscanf(p, "%d", &ret);
334	}
335
336	ClearNameValueList(&pdata);
337	return ret;
338}
339
340MINIUPNP_LIBSPEC int
341UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
342		    const char * extPort,
343		    const char * inPort,
344		    const char * inClient,
345		    const char * desc,
346		    const char * proto,
347		    const char * remoteHost,
348		    const char * leaseDuration)
349{
350	struct UPNParg * AddPortMappingArgs;
351	char * buffer;
352	int bufsize;
353	struct NameValueParserData pdata;
354	const char * resVal;
355	int ret;
356
357	if(!inPort || !inClient || !proto || !extPort)
358		return UPNPCOMMAND_INVALID_ARGS;
359
360	AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
361	AddPortMappingArgs[0].elt = "NewRemoteHost";
362	AddPortMappingArgs[0].val = remoteHost;
363	AddPortMappingArgs[1].elt = "NewExternalPort";
364	AddPortMappingArgs[1].val = extPort;
365	AddPortMappingArgs[2].elt = "NewProtocol";
366	AddPortMappingArgs[2].val = proto;
367	AddPortMappingArgs[3].elt = "NewInternalPort";
368	AddPortMappingArgs[3].val = inPort;
369	AddPortMappingArgs[4].elt = "NewInternalClient";
370	AddPortMappingArgs[4].val = inClient;
371	AddPortMappingArgs[5].elt = "NewEnabled";
372	AddPortMappingArgs[5].val = "1";
373	AddPortMappingArgs[6].elt = "NewPortMappingDescription";
374	AddPortMappingArgs[6].val = desc?desc:"libminiupnpc";
375	AddPortMappingArgs[7].elt = "NewLeaseDuration";
376	AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0";
377	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
378	                                "AddPortMapping", AddPortMappingArgs,
379	                                &bufsize))) {
380		free(AddPortMappingArgs);
381		return UPNPCOMMAND_HTTP_ERROR;
382	}
383	/*DisplayNameValueList(buffer, bufsize);*/
384	/*buffer[bufsize] = '\0';*/
385	/*puts(buffer);*/
386	ParseNameValue(buffer, bufsize, &pdata);
387	free(buffer); buffer = NULL;
388	resVal = GetValueFromNameValueList(&pdata, "errorCode");
389	if(resVal) {
390		/*printf("AddPortMapping errorCode = '%s'\n", resVal); */
391		ret = UPNPCOMMAND_UNKNOWN_ERROR;
392		sscanf(resVal, "%d", &ret);
393	} else {
394		ret = UPNPCOMMAND_SUCCESS;
395	}
396	ClearNameValueList(&pdata);
397	free(AddPortMappingArgs);
398	return ret;
399}
400
401MINIUPNP_LIBSPEC int
402UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
403		       const char * extPort,
404		       const char * inPort,
405		       const char * inClient,
406		       const char * desc,
407		       const char * proto,
408		       const char * remoteHost,
409		       const char * leaseDuration,
410		       char * reservedPort)
411{
412	struct UPNParg * AddPortMappingArgs;
413	char * buffer;
414	int bufsize;
415	struct NameValueParserData pdata;
416	const char * resVal;
417	int ret;
418
419	if(!inPort || !inClient || !proto || !extPort)
420		return UPNPCOMMAND_INVALID_ARGS;
421
422	AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
423	AddPortMappingArgs[0].elt = "NewRemoteHost";
424	AddPortMappingArgs[0].val = remoteHost;
425	AddPortMappingArgs[1].elt = "NewExternalPort";
426	AddPortMappingArgs[1].val = extPort;
427	AddPortMappingArgs[2].elt = "NewProtocol";
428	AddPortMappingArgs[2].val = proto;
429	AddPortMappingArgs[3].elt = "NewInternalPort";
430	AddPortMappingArgs[3].val = inPort;
431	AddPortMappingArgs[4].elt = "NewInternalClient";
432	AddPortMappingArgs[4].val = inClient;
433	AddPortMappingArgs[5].elt = "NewEnabled";
434	AddPortMappingArgs[5].val = "1";
435	AddPortMappingArgs[6].elt = "NewPortMappingDescription";
436	AddPortMappingArgs[6].val = desc?desc:"libminiupnpc";
437	AddPortMappingArgs[7].elt = "NewLeaseDuration";
438	AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0";
439	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
440	                                "AddAnyPortMapping", AddPortMappingArgs,
441	                                &bufsize))) {
442		free(AddPortMappingArgs);
443		return UPNPCOMMAND_HTTP_ERROR;
444	}
445	ParseNameValue(buffer, bufsize, &pdata);
446	free(buffer); buffer = NULL;
447	resVal = GetValueFromNameValueList(&pdata, "errorCode");
448	if(resVal) {
449		ret = UPNPCOMMAND_UNKNOWN_ERROR;
450		sscanf(resVal, "%d", &ret);
451	} else {
452		char *p;
453
454		p = GetValueFromNameValueList(&pdata, "NewReservedPort");
455		if(p) {
456			strncpy(reservedPort, p, 6);
457			reservedPort[5] = '\0';
458			ret = UPNPCOMMAND_SUCCESS;
459		} else {
460			ret = UPNPCOMMAND_INVALID_RESPONSE;
461		}
462	}
463	ClearNameValueList(&pdata);
464	free(AddPortMappingArgs);
465	return ret;
466}
467
468MINIUPNP_LIBSPEC int
469UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
470                       const char * extPort, const char * proto,
471                       const char * remoteHost)
472{
473	/*struct NameValueParserData pdata;*/
474	struct UPNParg * DeletePortMappingArgs;
475	char * buffer;
476	int bufsize;
477	struct NameValueParserData pdata;
478	const char * resVal;
479	int ret;
480
481	if(!extPort || !proto)
482		return UPNPCOMMAND_INVALID_ARGS;
483
484	DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg));
485	DeletePortMappingArgs[0].elt = "NewRemoteHost";
486	DeletePortMappingArgs[0].val = remoteHost;
487	DeletePortMappingArgs[1].elt = "NewExternalPort";
488	DeletePortMappingArgs[1].val = extPort;
489	DeletePortMappingArgs[2].elt = "NewProtocol";
490	DeletePortMappingArgs[2].val = proto;
491	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
492	                               "DeletePortMapping",
493	                               DeletePortMappingArgs, &bufsize))) {
494		free(DeletePortMappingArgs);
495		return UPNPCOMMAND_HTTP_ERROR;
496	}
497	/*DisplayNameValueList(buffer, bufsize);*/
498	ParseNameValue(buffer, bufsize, &pdata);
499	free(buffer); buffer = NULL;
500	resVal = GetValueFromNameValueList(&pdata, "errorCode");
501	if(resVal) {
502		ret = UPNPCOMMAND_UNKNOWN_ERROR;
503		sscanf(resVal, "%d", &ret);
504	} else {
505		ret = UPNPCOMMAND_SUCCESS;
506	}
507	ClearNameValueList(&pdata);
508	free(DeletePortMappingArgs);
509	return ret;
510}
511
512MINIUPNP_LIBSPEC int
513UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
514        		    const char * extPortStart, const char * extPortEnd,
515        		    const char * proto,
516			    const char * manage)
517{
518	struct UPNParg * DeletePortMappingArgs;
519	char * buffer;
520	int bufsize;
521	struct NameValueParserData pdata;
522	const char * resVal;
523	int ret;
524
525	if(!extPortStart || !extPortEnd || !proto || !manage)
526		return UPNPCOMMAND_INVALID_ARGS;
527
528	DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg));
529	DeletePortMappingArgs[0].elt = "NewStartPort";
530	DeletePortMappingArgs[0].val = extPortStart;
531	DeletePortMappingArgs[1].elt = "NewEndPort";
532	DeletePortMappingArgs[1].val = extPortEnd;
533	DeletePortMappingArgs[2].elt = "NewProtocol";
534	DeletePortMappingArgs[2].val = proto;
535	DeletePortMappingArgs[3].elt = "NewManage";
536	DeletePortMappingArgs[3].val = manage;
537
538	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
539	                                "DeletePortMappingRange",
540	                                DeletePortMappingArgs, &bufsize))) {
541		free(DeletePortMappingArgs);
542		return UPNPCOMMAND_HTTP_ERROR;
543	}
544	ParseNameValue(buffer, bufsize, &pdata);
545	free(buffer); buffer = NULL;
546	resVal = GetValueFromNameValueList(&pdata, "errorCode");
547	if(resVal) {
548		ret = UPNPCOMMAND_UNKNOWN_ERROR;
549		sscanf(resVal, "%d", &ret);
550	} else {
551		ret = UPNPCOMMAND_SUCCESS;
552	}
553	ClearNameValueList(&pdata);
554	free(DeletePortMappingArgs);
555	return ret;
556}
557
558MINIUPNP_LIBSPEC int
559UPNP_GetGenericPortMappingEntry(const char * controlURL,
560                                const char * servicetype,
561							 const char * index,
562							 char * extPort,
563							 char * intClient,
564							 char * intPort,
565							 char * protocol,
566							 char * desc,
567							 char * enabled,
568							 char * rHost,
569							 char * duration)
570{
571	struct NameValueParserData pdata;
572	struct UPNParg * GetPortMappingArgs;
573	char * buffer;
574	int bufsize;
575	char * p;
576	int r = UPNPCOMMAND_UNKNOWN_ERROR;
577	if(!index)
578		return UPNPCOMMAND_INVALID_ARGS;
579	intClient[0] = '\0';
580	intPort[0] = '\0';
581	GetPortMappingArgs = calloc(2, sizeof(struct UPNParg));
582	GetPortMappingArgs[0].elt = "NewPortMappingIndex";
583	GetPortMappingArgs[0].val = index;
584	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
585	                               "GetGenericPortMappingEntry",
586	                               GetPortMappingArgs, &bufsize))) {
587		free(GetPortMappingArgs);
588		return UPNPCOMMAND_HTTP_ERROR;
589	}
590	ParseNameValue(buffer, bufsize, &pdata);
591	free(buffer); buffer = NULL;
592
593	p = GetValueFromNameValueList(&pdata, "NewRemoteHost");
594	if(p && rHost)
595	{
596		strncpy(rHost, p, 64);
597		rHost[63] = '\0';
598	}
599	p = GetValueFromNameValueList(&pdata, "NewExternalPort");
600	if(p && extPort)
601	{
602		strncpy(extPort, p, 6);
603		extPort[5] = '\0';
604		r = UPNPCOMMAND_SUCCESS;
605	}
606	p = GetValueFromNameValueList(&pdata, "NewProtocol");
607	if(p && protocol)
608	{
609		strncpy(protocol, p, 4);
610		protocol[3] = '\0';
611	}
612	p = GetValueFromNameValueList(&pdata, "NewInternalClient");
613	if(p && intClient)
614	{
615		strncpy(intClient, p, 16);
616		intClient[15] = '\0';
617		r = 0;
618	}
619	p = GetValueFromNameValueList(&pdata, "NewInternalPort");
620	if(p && intPort)
621	{
622		strncpy(intPort, p, 6);
623		intPort[5] = '\0';
624	}
625	p = GetValueFromNameValueList(&pdata, "NewEnabled");
626	if(p && enabled)
627	{
628		strncpy(enabled, p, 4);
629		enabled[3] = '\0';
630	}
631	p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription");
632	if(p && desc)
633	{
634		strncpy(desc, p, 80);
635		desc[79] = '\0';
636	}
637	p = GetValueFromNameValueList(&pdata, "NewLeaseDuration");
638	if(p && duration)
639	{
640		strncpy(duration, p, 16);
641		duration[15] = '\0';
642	}
643	p = GetValueFromNameValueList(&pdata, "errorCode");
644	if(p) {
645		r = UPNPCOMMAND_UNKNOWN_ERROR;
646		sscanf(p, "%d", &r);
647	}
648	ClearNameValueList(&pdata);
649	free(GetPortMappingArgs);
650	return r;
651}
652
653MINIUPNP_LIBSPEC int
654UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
655                                   const char * servicetype,
656                                   unsigned int * numEntries)
657{
658 	struct NameValueParserData pdata;
659 	char * buffer;
660 	int bufsize;
661 	char* p;
662	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
663 	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
664	                                "GetPortMappingNumberOfEntries", 0,
665	                                &bufsize))) {
666		return UPNPCOMMAND_HTTP_ERROR;
667	}
668#ifdef DEBUG
669	DisplayNameValueList(buffer, bufsize);
670#endif
671 	ParseNameValue(buffer, bufsize, &pdata);
672	free(buffer); buffer = NULL;
673
674 	p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries");
675 	if(numEntries && p) {
676		*numEntries = 0;
677 		sscanf(p, "%u", numEntries);
678		ret = UPNPCOMMAND_SUCCESS;
679 	}
680
681	p = GetValueFromNameValueList(&pdata, "errorCode");
682	if(p) {
683		ret = UPNPCOMMAND_UNKNOWN_ERROR;
684		sscanf(p, "%d", &ret);
685	}
686
687 	ClearNameValueList(&pdata);
688	return ret;
689}
690
691/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
692 * the result is returned in the intClient and intPort strings
693 * please provide 16 and 6 bytes of data */
694MINIUPNP_LIBSPEC int
695UPNP_GetSpecificPortMappingEntry(const char * controlURL,
696                                 const char * servicetype,
697                                 const char * extPort,
698                                 const char * proto,
699                                 const char * remoteHost,
700                                 char * intClient,
701                                 char * intPort,
702                                 char * desc,
703                                 char * enabled,
704                                 char * leaseDuration)
705{
706	struct NameValueParserData pdata;
707	struct UPNParg * GetPortMappingArgs;
708	char * buffer;
709	int bufsize;
710	char * p;
711	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
712
713	if(!intPort || !intClient || !extPort || !proto)
714		return UPNPCOMMAND_INVALID_ARGS;
715
716	GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
717	GetPortMappingArgs[0].elt = "NewRemoteHost";
718	GetPortMappingArgs[0].val = remoteHost;
719	GetPortMappingArgs[1].elt = "NewExternalPort";
720	GetPortMappingArgs[1].val = extPort;
721	GetPortMappingArgs[2].elt = "NewProtocol";
722	GetPortMappingArgs[2].val = proto;
723	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
724	                                "GetSpecificPortMappingEntry",
725	                                GetPortMappingArgs, &bufsize))) {
726		free(GetPortMappingArgs);
727		return UPNPCOMMAND_HTTP_ERROR;
728	}
729	/*DisplayNameValueList(buffer, bufsize);*/
730	ParseNameValue(buffer, bufsize, &pdata);
731	free(buffer); buffer = NULL;
732
733	p = GetValueFromNameValueList(&pdata, "NewInternalClient");
734	if(p) {
735		strncpy(intClient, p, 16);
736		intClient[15] = '\0';
737		ret = UPNPCOMMAND_SUCCESS;
738	} else
739		intClient[0] = '\0';
740
741	p = GetValueFromNameValueList(&pdata, "NewInternalPort");
742	if(p) {
743		strncpy(intPort, p, 6);
744		intPort[5] = '\0';
745	} else
746		intPort[0] = '\0';
747
748	p = GetValueFromNameValueList(&pdata, "NewEnabled");
749	if(p && enabled) {
750		strncpy(enabled, p, 4);
751		enabled[3] = '\0';
752	}
753
754	p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription");
755	if(p && desc) {
756		strncpy(desc, p, 80);
757		desc[79] = '\0';
758	}
759
760	p = GetValueFromNameValueList(&pdata, "NewLeaseDuration");
761	if(p && leaseDuration)
762	{
763		strncpy(leaseDuration, p, 16);
764		leaseDuration[15] = '\0';
765	}
766
767	p = GetValueFromNameValueList(&pdata, "errorCode");
768	if(p) {
769		ret = UPNPCOMMAND_UNKNOWN_ERROR;
770		sscanf(p, "%d", &ret);
771	}
772
773	ClearNameValueList(&pdata);
774	free(GetPortMappingArgs);
775	return ret;
776}
777
778/* UPNP_GetListOfPortMappings()
779 *
780 * Possible UPNP Error codes :
781 * 606 Action not Authorized
782 * 730 PortMappingNotFound - no port mapping is found in the specified range.
783 * 733 InconsistantParameters - NewStartPort and NewEndPort values are not
784 *                              consistent.
785 */
786MINIUPNP_LIBSPEC int
787UPNP_GetListOfPortMappings(const char * controlURL,
788                           const char * servicetype,
789                           const char * startPort,
790                           const char * endPort,
791                           const char * protocol,
792                           const char * numberOfPorts,
793                           struct PortMappingParserData * data)
794{
795	struct NameValueParserData pdata;
796	struct UPNParg * GetListOfPortMappingsArgs;
797	const char * p;
798	char * buffer;
799	int bufsize;
800	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
801
802	if(!startPort || !endPort || !protocol)
803		return UPNPCOMMAND_INVALID_ARGS;
804
805	GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg));
806	GetListOfPortMappingsArgs[0].elt = "NewStartPort";
807	GetListOfPortMappingsArgs[0].val = startPort;
808	GetListOfPortMappingsArgs[1].elt = "NewEndPort";
809	GetListOfPortMappingsArgs[1].val = endPort;
810	GetListOfPortMappingsArgs[2].elt = "NewProtocol";
811	GetListOfPortMappingsArgs[2].val = protocol;
812	GetListOfPortMappingsArgs[3].elt = "NewManage";
813	GetListOfPortMappingsArgs[3].val = "1";
814	GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts";
815	GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000";
816
817	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
818	                                "GetListOfPortMappings",
819	                                GetListOfPortMappingsArgs, &bufsize))) {
820		free(GetListOfPortMappingsArgs);
821		return UPNPCOMMAND_HTTP_ERROR;
822	}
823	free(GetListOfPortMappingsArgs);
824
825	/*DisplayNameValueList(buffer, bufsize);*/
826	ParseNameValue(buffer, bufsize, &pdata);
827	free(buffer); buffer = NULL;
828
829	/*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/
830	/*if(p) {
831		printf("NewPortListing : %s\n", p);
832	}*/
833	/*printf("NewPortListing(%d chars) : %s\n",
834	       pdata.portListingLength, pdata.portListing);*/
835	if(pdata.portListing)
836	{
837		/*struct PortMapping * pm;
838		int i = 0;*/
839		ParsePortListing(pdata.portListing, pdata.portListingLength,
840		                 data);
841		ret = UPNPCOMMAND_SUCCESS;
842		/*
843		for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next)
844		{
845			printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n",
846			       i, pm->protocol, pm->externalPort, pm->internalClient,
847			       pm->internalPort,
848			       pm->description, pm->remoteHost);
849			i++;
850		}
851		*/
852		/*FreePortListing(&data);*/
853	}
854
855	p = GetValueFromNameValueList(&pdata, "errorCode");
856	if(p) {
857		ret = UPNPCOMMAND_UNKNOWN_ERROR;
858		sscanf(p, "%d", &ret);
859	}
860	ClearNameValueList(&pdata);
861
862	/*printf("%.*s", bufsize, buffer);*/
863
864	return ret;
865}
866
867/* IGD:2, functions for service WANIPv6FirewallControl:1 */
868MINIUPNP_LIBSPEC int
869UPNP_GetFirewallStatus(const char * controlURL,
870				const char * servicetype,
871				int * firewallEnabled,
872				int * inboundPinholeAllowed)
873{
874	struct NameValueParserData pdata;
875	char * buffer;
876	int bufsize;
877	char * fe, *ipa, *p;
878	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
879
880	if(!firewallEnabled || !inboundPinholeAllowed)
881		return UPNPCOMMAND_INVALID_ARGS;
882
883	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
884	                           "GetFirewallStatus", 0, &bufsize);
885	if(!buffer) {
886		return UPNPCOMMAND_HTTP_ERROR;
887	}
888	ParseNameValue(buffer, bufsize, &pdata);
889	free(buffer); buffer = NULL;
890	fe = GetValueFromNameValueList(&pdata, "FirewallEnabled");
891	ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed");
892	if(ipa && fe)
893		ret = UPNPCOMMAND_SUCCESS;
894	if(fe)
895		*firewallEnabled = my_atoui(fe);
896	/*else
897		*firewallEnabled = 0;*/
898	if(ipa)
899		*inboundPinholeAllowed = my_atoui(ipa);
900	/*else
901		*inboundPinholeAllowed = 0;*/
902	p = GetValueFromNameValueList(&pdata, "errorCode");
903	if(p)
904	{
905		ret = UPNPCOMMAND_UNKNOWN_ERROR;
906		sscanf(p, "%d", &ret);
907	}
908	ClearNameValueList(&pdata);
909	return ret;
910}
911
912MINIUPNP_LIBSPEC int
913UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
914                    const char * remoteHost,
915                    const char * remotePort,
916                    const char * intClient,
917                    const char * intPort,
918                    const char * proto,
919                    int * opTimeout)
920{
921	struct UPNParg * GetOutboundPinholeTimeoutArgs;
922	char * buffer;
923	int bufsize;
924	struct NameValueParserData pdata;
925	const char * resVal;
926	char * p;
927	int ret;
928
929	if(!intPort || !intClient || !proto || !remotePort || !remoteHost)
930		return UPNPCOMMAND_INVALID_ARGS;
931
932	GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg));
933	GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost";
934	GetOutboundPinholeTimeoutArgs[0].val = remoteHost;
935	GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort";
936	GetOutboundPinholeTimeoutArgs[1].val = remotePort;
937	GetOutboundPinholeTimeoutArgs[2].elt = "Protocol";
938	GetOutboundPinholeTimeoutArgs[2].val = proto;
939	GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort";
940	GetOutboundPinholeTimeoutArgs[3].val = intPort;
941	GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient";
942	GetOutboundPinholeTimeoutArgs[4].val = intClient;
943	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
944	                           "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize);
945	if(!buffer)
946		return UPNPCOMMAND_HTTP_ERROR;
947	ParseNameValue(buffer, bufsize, &pdata);
948	free(buffer); buffer = NULL;
949	resVal = GetValueFromNameValueList(&pdata, "errorCode");
950	if(resVal)
951	{
952		ret = UPNPCOMMAND_UNKNOWN_ERROR;
953		sscanf(resVal, "%d", &ret);
954	}
955	else
956	{
957		ret = UPNPCOMMAND_SUCCESS;
958		p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout");
959		if(p)
960			*opTimeout = my_atoui(p);
961	}
962	ClearNameValueList(&pdata);
963	free(GetOutboundPinholeTimeoutArgs);
964	return ret;
965}
966
967MINIUPNP_LIBSPEC int
968UPNP_AddPinhole(const char * controlURL, const char * servicetype,
969                    const char * remoteHost,
970                    const char * remotePort,
971                    const char * intClient,
972                    const char * intPort,
973                    const char * proto,
974                    const char * leaseTime,
975                    char * uniqueID)
976{
977	struct UPNParg * AddPinholeArgs;
978	char * buffer;
979	int bufsize;
980	struct NameValueParserData pdata;
981	const char * resVal;
982	char * p;
983	int ret;
984
985	if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime)
986		return UPNPCOMMAND_INVALID_ARGS;
987
988	AddPinholeArgs = calloc(7, sizeof(struct UPNParg));
989	/* RemoteHost can be wilcarded */
990	if(strncmp(remoteHost, "empty", 5)==0)
991	{
992		AddPinholeArgs[0].elt = "RemoteHost";
993		AddPinholeArgs[0].val = "";
994	}
995	else
996	{
997		AddPinholeArgs[0].elt = "RemoteHost";
998		AddPinholeArgs[0].val = remoteHost;
999	}
1000	AddPinholeArgs[1].elt = "RemotePort";
1001	AddPinholeArgs[1].val = remotePort;
1002	AddPinholeArgs[2].elt = "Protocol";
1003	AddPinholeArgs[2].val = proto;
1004	AddPinholeArgs[3].elt = "InternalPort";
1005	AddPinholeArgs[3].val = intPort;
1006	if(strncmp(intClient, "empty", 5)==0)
1007	{
1008		AddPinholeArgs[4].elt = "InternalClient";
1009		AddPinholeArgs[4].val = "";
1010	}
1011	else
1012	{
1013		AddPinholeArgs[4].elt = "InternalClient";
1014		AddPinholeArgs[4].val = intClient;
1015	}
1016	AddPinholeArgs[5].elt = "LeaseTime";
1017	AddPinholeArgs[5].val = leaseTime;
1018	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
1019	                           "AddPinhole", AddPinholeArgs, &bufsize);
1020	if(!buffer)
1021		return UPNPCOMMAND_HTTP_ERROR;
1022	ParseNameValue(buffer, bufsize, &pdata);
1023	free(buffer); buffer = NULL;
1024	p = GetValueFromNameValueList(&pdata, "UniqueID");
1025	if(p)
1026	{
1027		strncpy(uniqueID, p, 8);
1028		uniqueID[7] = '\0';
1029	}
1030	resVal = GetValueFromNameValueList(&pdata, "errorCode");
1031	if(resVal)
1032	{
1033		/*printf("AddPortMapping errorCode = '%s'\n", resVal);*/
1034		ret = UPNPCOMMAND_UNKNOWN_ERROR;
1035		sscanf(resVal, "%d", &ret);
1036	}
1037	else
1038	{
1039		ret = UPNPCOMMAND_SUCCESS;
1040	}
1041	ClearNameValueList(&pdata);
1042	free(AddPinholeArgs);
1043	return ret;
1044}
1045
1046MINIUPNP_LIBSPEC int
1047UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
1048                    const char * uniqueID,
1049                    const char * leaseTime)
1050{
1051	struct UPNParg * UpdatePinholeArgs;
1052	char * buffer;
1053	int bufsize;
1054	struct NameValueParserData pdata;
1055	const char * resVal;
1056	int ret;
1057
1058	if(!uniqueID || !leaseTime)
1059		return UPNPCOMMAND_INVALID_ARGS;
1060
1061	UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg));
1062	UpdatePinholeArgs[0].elt = "UniqueID";
1063	UpdatePinholeArgs[0].val = uniqueID;
1064	UpdatePinholeArgs[1].elt = "NewLeaseTime";
1065	UpdatePinholeArgs[1].val = leaseTime;
1066	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
1067	                           "UpdatePinhole", UpdatePinholeArgs, &bufsize);
1068	if(!buffer)
1069		return UPNPCOMMAND_HTTP_ERROR;
1070	ParseNameValue(buffer, bufsize, &pdata);
1071	free(buffer); buffer = NULL;
1072	resVal = GetValueFromNameValueList(&pdata, "errorCode");
1073	if(resVal)
1074	{
1075		/*printf("AddPortMapping errorCode = '%s'\n", resVal); */
1076		ret = UPNPCOMMAND_UNKNOWN_ERROR;
1077		sscanf(resVal, "%d", &ret);
1078	}
1079	else
1080	{
1081		ret = UPNPCOMMAND_SUCCESS;
1082	}
1083	ClearNameValueList(&pdata);
1084	free(UpdatePinholeArgs);
1085	return ret;
1086}
1087
1088MINIUPNP_LIBSPEC int
1089UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID)
1090{
1091	/*struct NameValueParserData pdata;*/
1092	struct UPNParg * DeletePinholeArgs;
1093	char * buffer;
1094	int bufsize;
1095	struct NameValueParserData pdata;
1096	const char * resVal;
1097	int ret;
1098
1099	if(!uniqueID)
1100		return UPNPCOMMAND_INVALID_ARGS;
1101
1102	DeletePinholeArgs = calloc(2, sizeof(struct UPNParg));
1103	DeletePinholeArgs[0].elt = "UniqueID";
1104	DeletePinholeArgs[0].val = uniqueID;
1105	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
1106	                           "DeletePinhole", DeletePinholeArgs, &bufsize);
1107	if(!buffer)
1108		return UPNPCOMMAND_HTTP_ERROR;
1109	/*DisplayNameValueList(buffer, bufsize);*/
1110	ParseNameValue(buffer, bufsize, &pdata);
1111	free(buffer); buffer = NULL;
1112	resVal = GetValueFromNameValueList(&pdata, "errorCode");
1113	if(resVal)
1114	{
1115		ret = UPNPCOMMAND_UNKNOWN_ERROR;
1116		sscanf(resVal, "%d", &ret);
1117	}
1118	else
1119	{
1120		ret = UPNPCOMMAND_SUCCESS;
1121	}
1122	ClearNameValueList(&pdata);
1123	free(DeletePinholeArgs);
1124	return ret;
1125}
1126
1127MINIUPNP_LIBSPEC int
1128UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
1129                                 const char * uniqueID, int * isWorking)
1130{
1131	struct NameValueParserData pdata;
1132	struct UPNParg * CheckPinholeWorkingArgs;
1133	char * buffer;
1134	int bufsize;
1135	char * p;
1136	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
1137
1138	if(!uniqueID)
1139		return UPNPCOMMAND_INVALID_ARGS;
1140
1141	CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg));
1142	CheckPinholeWorkingArgs[0].elt = "UniqueID";
1143	CheckPinholeWorkingArgs[0].val = uniqueID;
1144	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
1145	                           "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize);
1146	if(!buffer)
1147		return UPNPCOMMAND_HTTP_ERROR;
1148	ParseNameValue(buffer, bufsize, &pdata);
1149	free(buffer); buffer = NULL;
1150
1151	p = GetValueFromNameValueList(&pdata, "IsWorking");
1152	if(p)
1153	{
1154		*isWorking=my_atoui(p);
1155		ret = UPNPCOMMAND_SUCCESS;
1156	}
1157	else
1158		*isWorking = 0;
1159
1160	p = GetValueFromNameValueList(&pdata, "errorCode");
1161	if(p)
1162	{
1163		ret = UPNPCOMMAND_UNKNOWN_ERROR;
1164		sscanf(p, "%d", &ret);
1165	}
1166
1167	ClearNameValueList(&pdata);
1168	free(CheckPinholeWorkingArgs);
1169	return ret;
1170}
1171
1172MINIUPNP_LIBSPEC int
1173UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
1174                                 const char * uniqueID, int * packets)
1175{
1176	struct NameValueParserData pdata;
1177	struct UPNParg * GetPinholePacketsArgs;
1178	char * buffer;
1179	int bufsize;
1180	char * p;
1181	int ret = UPNPCOMMAND_UNKNOWN_ERROR;
1182
1183	if(!uniqueID)
1184		return UPNPCOMMAND_INVALID_ARGS;
1185
1186	GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg));
1187	GetPinholePacketsArgs[0].elt = "UniqueID";
1188	GetPinholePacketsArgs[0].val = uniqueID;
1189	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
1190	                           "GetPinholePackets", GetPinholePacketsArgs, &bufsize);
1191	if(!buffer)
1192		return UPNPCOMMAND_HTTP_ERROR;
1193	ParseNameValue(buffer, bufsize, &pdata);
1194	free(buffer); buffer = NULL;
1195
1196	p = GetValueFromNameValueList(&pdata, "PinholePackets");
1197	if(p)
1198	{
1199		*packets=my_atoui(p);
1200		ret = UPNPCOMMAND_SUCCESS;
1201	}
1202
1203	p = GetValueFromNameValueList(&pdata, "errorCode");
1204	if(p)
1205	{
1206		ret = UPNPCOMMAND_UNKNOWN_ERROR;
1207		sscanf(p, "%d", &ret);
1208	}
1209
1210	ClearNameValueList(&pdata);
1211	free(GetPinholePacketsArgs);
1212	return ret;
1213}
1214
1215
1216