1/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */
2/* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2011-2020 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
7#include <string.h>
8#include <stdlib.h>
9#ifdef DEBUG
10#include <stdio.h>
11#endif /* DEBUG */
12#include "portlistingparse.h"
13#include "minixml.h"
14
15#if defined(__HAIKU__)
16/* rename our private function because Haiku already defines a atoui() function */
17#define atoui atoui2
18#endif
19
20/* list of the elements */
21static const struct {
22 const portMappingElt code;
23 const char * const str;
24} elements[] = {
25 { PortMappingEntry, "PortMappingEntry"},
26 { NewRemoteHost, "NewRemoteHost"},
27 { NewExternalPort, "NewExternalPort"},
28 { NewProtocol, "NewProtocol"},
29 { NewInternalPort, "NewInternalPort"},
30 { NewInternalClient, "NewInternalClient"},
31 { NewEnabled, "NewEnabled"},
32 { NewDescription, "NewDescription"},
33 { NewLeaseTime, "NewLeaseTime"},
34 { PortMappingEltNone, NULL}
35};
36
37/* Helper function */
38static UNSIGNED_INTEGER
39atoui(const char * p, int l)
40{
41 UNSIGNED_INTEGER r = 0;
42 while(l > 0 && *p)
43 {
44 if(*p >= '0' && *p <= '9')
45 r = r*10 + (*p - '0');
46 else
47 break;
48 p++;
49 l--;
50 }
51 return r;
52}
53
54/* Start element handler */
55static void
56startelt(void * d, const char * name, int l)
57{
58 int i;
59 struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
60 pdata->curelt = PortMappingEltNone;
61 for(i = 0; elements[i].str; i++)
62 {
63 if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0)
64 {
65 pdata->curelt = elements[i].code;
66 break;
67 }
68 }
69 if(pdata->curelt == PortMappingEntry)
70 {
71 struct PortMapping * pm;
72 pm = calloc(1, sizeof(struct PortMapping));
73 if(pm == NULL)
74 {
75 /* malloc error */
76#ifdef DEBUG
77 fprintf(stderr, "%s: error allocating memory",
78 "startelt");
79#endif /* DEBUG */
80 return;
81 }
82 pm->l_next = pdata->l_head; /* insert in list */
83 pdata->l_head = pm;
84 }
85}
86
87/* End element handler */
88static void
89endelt(void * d, const char * name, int l)
90{
91 struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
92 (void)name;
93 (void)l;
94 pdata->curelt = PortMappingEltNone;
95}
96
97/* Data handler */
98static void
99data(void * d, const char * data, int l)
100{
101 struct PortMapping * pm;
102 struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
103 pm = pdata->l_head;
104 if(!pm)
105 return;
106 if(l > 63)
107 l = 63;
108 switch(pdata->curelt)
109 {
110 case NewRemoteHost:
111 memcpy(pm->remoteHost, data, l);
112 pm->remoteHost[l] = '\0';
113 break;
114 case NewExternalPort:
115 pm->externalPort = (unsigned short)atoui(data, l);
116 break;
117 case NewProtocol:
118 if(l > 3)
119 l = 3;
120 memcpy(pm->protocol, data, l);
121 pm->protocol[l] = '\0';
122 break;
123 case NewInternalPort:
124 pm->internalPort = (unsigned short)atoui(data, l);
125 break;
126 case NewInternalClient:
127 memcpy(pm->internalClient, data, l);
128 pm->internalClient[l] = '\0';
129 break;
130 case NewEnabled:
131 pm->enabled = (unsigned char)atoui(data, l);
132 break;
133 case NewDescription:
134 memcpy(pm->description, data, l);
135 pm->description[l] = '\0';
136 break;
137 case NewLeaseTime:
138 pm->leaseTime = atoui(data, l);
139 break;
140 default:
141 break;
142 }
143}
144
145
146/* Parse the PortMappingList XML document for IGD version 2
147 */
148void
149ParsePortListing(const char * buffer, int bufsize,
150 struct PortMappingParserData * pdata)
151{
152 struct xmlparser parser;
153
154 memset(pdata, 0, sizeof(struct PortMappingParserData));
155 /* init xmlparser */
156 parser.xmlstart = buffer;
157 parser.xmlsize = bufsize;
158 parser.data = pdata;
159 parser.starteltfunc = startelt;
160 parser.endeltfunc = endelt;
161 parser.datafunc = data;
162 parser.attfunc = 0;
163 parsexml(&parser);
164}
165
166void
167FreePortListing(struct PortMappingParserData * pdata)
168{
169 struct PortMapping * pm;
170 while((pm = pdata->l_head) != NULL)
171 {
172 /* remove from list */
173 pdata->l_head = pm->l_next;
174 free(pm);
175 }
176}
177
178