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 |
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 |
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 |
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 |
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 |
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 |
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 | |