Annotation of embedaddon/miniupnpd/miniupnpc-libevent/upnpc-libevent.c, revision 1.1.1.1
1.1 misho 1: /* $Id: upnpc-libevent.c,v 1.11 2014/12/02 13:33:42 nanard Exp $ */
2: /* miniupnpc-libevent
3: * Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
4: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
5: *
6: * Permission to use, copy, modify, and/or distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
17:
18: #include <stdio.h>
19: #include <string.h>
20: #include <signal.h>
21: #include <unistd.h>
22: #include <sys/socket.h>
23: #include <netinet/in.h>
24: #include <arpa/inet.h>
25:
26: #include "miniupnpc-libevent.h"
27:
28: static struct event_base *base = NULL;
29: static char local_address[32];
30:
31: static void sighandler(int signal)
32: {
33: (void)signal;
34: /*printf("signal %d\n", signal);*/
35: if(base != NULL)
36: event_base_loopbreak(base);
37: }
38:
39: /* ready callback */
40: static void ready(int code, upnpc_t * p, upnpc_device_t * d, void * data)
41: {
42: (void)data; (void)p;
43:
44: if(code == 200) {
45: printf("READY ! %d\n", code);
46: printf(" root_desc_location='%s'\n", d->root_desc_location);
47: /* 1st request */
48: #ifdef ENABLE_UPNP_EVENTS
49: upnpc_event_subscribe(d);
50: #else
51: upnpc_get_status_info(d);
52: #endif /* ENABLE_UPNP_EVENTS */
53: } else {
54: printf("DISCOVER ERROR : %d\n", code);
55: switch(code) {
56: case UPNPC_ERR_NO_DEVICE_FOUND:
57: printf("UPNPC_ERR_NO_DEVICE_FOUND\n");
58: break;
59: case UPNPC_ERR_ROOT_DESC_ERROR:
60: printf("UPNPC_ERR_ROOT_DESC_ERROR\n");
61: break;
62: case 404:
63: printf("Root desc not found (404)\n");
64: break;
65: default:
66: printf("unknown error\n");
67: }
68: }
69: }
70:
71: static enum {
72: EGetStatusInfo = 0,
73: EGetExtIp,
74: EGetMaxRate,
75: EAddPortMapping,
76: EDeletePortMapping,
77: EFinished
78: } state = EGetStatusInfo;
79:
80: /* soap callback */
81: static void soap(int code, upnpc_t * p, upnpc_device_t * d, void * data)
82: {
83: (void)data; (void)p;
84:
85: printf("SOAP ! %d\n", code);
86: if(code == 200) {
87: switch(state) {
88: case EGetStatusInfo:
89: printf("ConnectionStatus=%s\n", GetValueFromNameValueList(&d->soap_response_data, "NewConnectionStatus"));
90: printf("LastConnectionError=%s\n", GetValueFromNameValueList(&d->soap_response_data, "NewLastConnectionError"));
91: printf("Uptime=%s\n", GetValueFromNameValueList(&d->soap_response_data, "NewUptime"));
92: upnpc_get_external_ip_address(d);
93: state = EGetExtIp;
94: break;
95: case EGetExtIp:
96: printf("ExternalIpAddress=%s\n", GetValueFromNameValueList(&d->soap_response_data, "NewExternalIPAddress"));
97: upnpc_get_link_layer_max_rate(d);
98: state = EGetMaxRate;
99: break;
100: case EGetMaxRate:
101: printf("DownStream MaxBitRate = %s\t", GetValueFromNameValueList(&d->soap_response_data, "NewLayer1DownstreamMaxBitRate"));
102: upnpc_add_port_mapping(d, NULL, 60001, 60002, local_address, "TCP", "test port mapping", 0);
103: printf("UpStream MaxBitRate = %s\n", GetValueFromNameValueList(&d->soap_response_data, "NewLayer1UpstreamMaxBitRate"));
104: state = EAddPortMapping;
105: break;
106: case EAddPortMapping:
107: printf("AddPortMapping OK!\n");
108: upnpc_delete_port_mapping(d, NULL, 60001, "TCP");
109: state = EDeletePortMapping;
110: break;
111: case EDeletePortMapping:
112: printf("DeletePortMapping OK!\n");
113: state = EFinished;
114: break;
115: default:
116: printf("EFinished : breaking\n");
117: event_base_loopbreak(base);
118: }
119: } else {
120: printf("SOAP error :\n");
121: printf(" faultcode='%s'\n", GetValueFromNameValueList(&d->soap_response_data, "faultcode"));
122: printf(" faultstring='%s'\n", GetValueFromNameValueList(&d->soap_response_data, "faultstring"));
123: printf(" errorCode=%s\n", GetValueFromNameValueList(&d->soap_response_data, "errorCode"));
124: printf(" errorDescription='%s'\n", GetValueFromNameValueList(&d->soap_response_data, "errorDescription"));
125: event_base_loopbreak(base);
126: }
127: }
128:
129: #ifdef ENABLE_UPNP_EVENTS
130: /* event callback */
131: static void event_callback(upnpc_t * p, upnpc_device_t * d, void * data,
132: const char * service_id, const char * property_name, const char * property_value)
133: {
134: (void)p; (void)d; (void)data;
135: printf("PROPERTY VALUE CHANGE (service=%s): %s=%s\n", service_id, property_name, property_value);
136: }
137: #endif /* ENABLE_UPNP_EVENTS */
138:
139: /* use a UDP "connection" to 8.8.8.8
140: * to retrieve local address */
141: int find_local_address(void)
142: {
143: int s;
144: struct sockaddr_in local, remote;
145: socklen_t len;
146:
147: s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
148: if(s < 0) {
149: perror("socket");
150: return -1;
151: }
152:
153: memset(&local, 0, sizeof(local));
154: memset(&remote, 0, sizeof(remote));
155: /* bind to local port 4567 */
156: local.sin_family = AF_INET;
157: local.sin_port = htons(4567);
158: local.sin_addr.s_addr = htonl(INADDR_ANY);
159: if(bind(s, (struct sockaddr *)&local, sizeof(local)) < 0) {
160: perror("bind");
161: return -1;
162: }
163: /* "connect" google's DNS server at 8.8.8.8 port 4567 */
164: remote.sin_family = AF_INET;
165: remote.sin_port = htons(4567);
166: remote.sin_addr.s_addr = inet_addr("8.8.8.8");
167: if(connect(s, (struct sockaddr *)&remote, sizeof(remote)) < 0) {
168: perror("connect");
169: return -1;
170: }
171: len = sizeof(local);
172: if(getsockname(s, (struct sockaddr *)&local, &len) < 0) {
173: perror("getsockname");
174: return -1;
175: }
176: if(inet_ntop(AF_INET, &(local.sin_addr), local_address, sizeof(local_address)) == NULL) {
177: perror("inet_ntop");
178: return -1;
179: }
180: printf("local address : %s\n", local_address);
181: close(s);
182: return 0;
183: }
184:
185: /* program entry point */
186:
187: int main(int argc, char * * argv)
188: {
189: struct sigaction sa;
190: upnpc_t upnp;
191: char * multicast_if = NULL;
192:
193: if(argc > 1) {
194: multicast_if = argv[1];
195: }
196:
197: memset(&sa, 0, sizeof(struct sigaction));
198: sa.sa_handler = sighandler;
199: if(sigaction(SIGINT, &sa, NULL) < 0) {
200: perror("sigaction");
201: }
202:
203: if(find_local_address() < 0) {
204: fprintf(stderr, "failed to get local address\n");
205: return 1;
206: }
207: #ifdef DEBUG
208: event_enable_debug_mode();
209: #if LIBEVENT_VERSION_NUMBER >= 0x02010100
210: event_enable_debug_logging(EVENT_DBG_ALL); /* Libevent 2.1.1 */
211: #endif /* LIBEVENT_VERSION_NUMBER >= 0x02010100 */
212: #endif /* DEBUG */
213: printf("Using libevent %s\n", event_get_version());
214: if(LIBEVENT_VERSION_NUMBER != event_get_version_number()) {
215: fprintf(stderr, "WARNING build using libevent %s", LIBEVENT_VERSION);
216: }
217:
218: base = event_base_new();
219: if(base == NULL) {
220: fprintf(stderr, "event_base_new() failed\n");
221: return 1;
222: }
223: #ifdef DEBUG
224: printf("Using Libevent with backend method %s.\n",
225: event_base_get_method(base));
226: #endif /* DEBUG */
227:
228: if(upnpc_init(&upnp, base, multicast_if, ready, soap, &upnp) != UPNPC_OK) {
229: fprintf(stderr, "upnpc_init() failed\n");
230: return 1;
231: }
232: upnpc_set_local_address(&upnp, local_address, 50000);
233: #ifdef ENABLE_UPNP_EVENTS
234: upnpc_set_event_callback(&upnp, event_callback);
235: #endif /* ENABLE_UPNP_EVENTS */
236: if(upnpc_start(&upnp) != UPNPC_OK) {
237: fprintf(stderr, "upnp_start() failed\n");
238: return 1;
239: }
240:
241: event_base_dispatch(base); /* TODO : check return value */
242: printf("finishing...\n");
243:
244: upnpc_finalize(&upnp);
245: event_base_free(base);
246:
247: #if LIBEVENT_VERSION_NUMBER >= 0x02010100
248: libevent_global_shutdown(); /* Libevent 2.1.1 */
249: #endif
250: return 0;
251: }
252:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>