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