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 */
21 static 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 */
38 static UNSIGNED_INTEGER
atoui(const char * p,int l)39 atoui(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 */
55 static void
startelt(void * d,const char * name,int l)56 startelt(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 */
88 static void
endelt(void * d,const char * name,int l)89 endelt(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 */
98 static void
data(void * d,const char * data,int l)99 data(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 */
148 void
ParsePortListing(const char * buffer,int bufsize,struct PortMappingParserData * pdata)149 ParsePortListing(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
166 void
FreePortListing(struct PortMappingParserData * pdata)167 FreePortListing(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