예제 #1
0
/* 
 * UPnP portable main loop.
 * It initializes the UPnP protocol and event variables.
 * And loop handler the UPnP incoming requests.
 */
void
upnp_mainloop()
{
	UPNP_CONTEXT *context = &upnp_context;

	/* initialize upnp */
	upnp_init(context);

	/* main loop */
	while (1) {
		switch (upnp_flag) {
		case UPNP_FLAG_SHUTDOWN:
			upnp_shutdown(context);

			upnp_syslog(LOG_INFO, "UPnP shutdown!");
			return;

		case UPNP_FLAG_RESTART:
			upnp_shutdown(context);
			upnp_init(context);

			upnp_syslog(LOG_INFO, "UPnP restart!");
			break;

		case 0:
		default:
			upnp_dispatch(context);
			break;
		}
	}

	return;
}
예제 #2
0
/* Do UPnP interface initialization */
int
upnp_ifattach(UPNP_CONTEXT *context, char *ifname, UPNP_DEVICE *device)
{
	UPNP_INTERFACE	*ifp;

	/* Allocate interface space */
	ifp = (UPNP_INTERFACE *)malloc(sizeof(*ifp));
	if (ifp == 0)
		return 0;

	memset(ifp, 0, sizeof(*ifp));

	/* Setup context */
	strncpy(ifp->ifname, ifname, sizeof(ifp->ifname));
	ifp->ifname[sizeof(ifp->ifname)-1] = '\0';
	ifp->http_sock = -1;

	if (get_if_ipaddr(ifp) != 0) {
		free(ifp);
		return 0;
	}

	/* Do prepend */
	ifp->next = context->iflist;
	context->iflist = ifp;

	/* Attache device */
	if (context->ssdp_sock == -1) {
		if (ssdp_init(context) != 0) {
			free(ifp);
			return -1;
		}
	}

	context->focus_ifp = ifp;

	/* Perform per interface protocol initialization */
	if (upnp_http_init(context) != 0) {
		upnp_syslog(LOG_ERR, "upnp_http_init::%s init error!", ifp->ifname);
		return -1;
	}

	if (ssdp_add_multi(context) == -1) {
		upnp_syslog(LOG_ERR, "ssdp_add_multi::%s error!", ifp->ifname);
		return -1;
	}

	/*
	 * Hook device table to each interface.
	 * The init function of each device
	 * intialize the event variables, and send SSDP ALIVE to each
	 * interface
	 */
	if (upnp_device_attach(context, device) == -1) {
		upnp_syslog(LOG_ERR, "upnp_device_attach::%s(%s) error!",
			device->root_device_xml, ifp->ifname);
		return -1;
	}
	return 0;
}
예제 #3
0
/* Shutdown all the UPnP interfaces */
void
upnp_deinit(UPNP_CONTEXT *context)
{
	UPNP_INTERFACE	*ifp;

	while ((ifp = context->iflist) != 0) {

		context->focus_ifp = ifp;

		/* Unhook device database */
		upnp_device_detach(context, ifp->device);

		/* shutdown interface protocol */
		upnp_http_shutdown(context);

		ssdp_del_multi(context);

		/* Drop this link and free */
		context->iflist = ifp->next;

		free(ifp);
	}

	/* Shutdown the mutlicast receive socket */
	ssdp_shutdown(context);

	upnp_syslog(LOG_INFO, "UPnP daemon stopped");

	free(context);
	return;
}
예제 #4
0
/* Read data from socket until end of header of error occurs */
static int
read_header(UPNP_CONTEXT *context, struct upnp_method *methods)
{
	int buf_size;
	int n;

	while (get_msghdr(context)) {
		/* check buffer size */
		buf_size = sizeof(context->buf) - context->end;
		if (buf_size <= 0) {
			upnp_syslog(LOG_ERR, "Cannot get enough buffer");
			context->status = R_BAD_REQUEST;
			break;
		}

		/* read socket into the buffer */
		n = read_sock(context->fd, &context->buf[context->end], buf_size, 0);
		if (n <= 0) {
			context->status = R_ERROR;
			return -2;
		}

		/* Move end */
		context->end += n;
	}

	if (context->status != 0)
		return -1;

	context->content = &context->buf[context->index];
	context->content_len = context->end - context->index;
	return 0;
}
예제 #5
0
/* Parse the URI */
int
parse_uri(UPNP_CONTEXT *context, struct upnp_method *methods)
{
	char *p = context->url;
	int pos;

	/* skip white spaces */
	while (*p == ' ' || *p == '\t')
		p++;

	pos = strcspn(p, "\t ");

	context->url = p;
	context->url[pos] = 0;

	/* SSDP only accepts "*" */
	if (context->method == METHOD_MSEARCH && strcmp(context->url, "*") != 0) {
		upnp_syslog(LOG_ERR, "SSDP method=%d, URL=%s", context->method, context->url);
		return -1;
	}

	/* skip URL and white spaces */
	p += pos+1;
	while (*p == ' ' || *p == '\t')
		p++;

	/* also check HTTP version */
	if (memcmp(p, "HTTP/1.0", 8) != 0 &&
	    memcmp(p, "HTTP/1.1", 8) != 0) {
		return -1;
	}

	return 0;
}
예제 #6
0
void
upnp_device_detach(UPNP_CONTEXT *context, UPNP_DEVICE *device)
{
	UPNP_INTERFACE	*ifp = context->focus_ifp;

	upnp_syslog(LOG_INFO, "%s: detach %s", ifp->ifname, device->root_device_xml);

	if (!ifp->device || ifp->device != device)
		return;

	/* Do device specific stop function */
	if (device->close)
		(*device->close)(context);

	/* Clear event variables and subscribers */
	gena_shutdown(context);

	/* Send byebye */
	ssdp_byebye(context);

	/* Free per interface advertise list */
	upnp_device_advlist_deinit(context);

	/* detach it */
	ifp->device = 0;

	return;
}
예제 #7
0
int
upnp_device_attach(UPNP_CONTEXT *context, UPNP_DEVICE *device)
{
	UPNP_INTERFACE *ifp = context->focus_ifp;

	upnp_syslog(LOG_INFO, "%s: attach %s", ifp->ifname, device->root_device_xml);

	/* Check if the device has already attached? */
	if (ifp->device && ifp->device == device)
		return 0;

	ifp->device = device;

	/* Setup per interface UUIDs */
	upnp_device_advlist_init(context);

	/* Remove this chain, if open error */
	if (device->open && (*device->open)(context) != 0) {
		ifp->device = 0;
		return -1;
	}

	/* Initialize gena event variable */
	gena_init(context);

	/* Send alive here */
	ssdp_alive(context);

	return 0;
}
예제 #8
0
int
upnp_msg_save(UPNP_CONTEXT *context, char *name, char *value)
{
	UPNP_MSG *msg;

	/* FIXEME: Duplicate name, value to other buffer
	 * seems safer.
	 */

	/* Find in list */
	for (msg = context->msglist; msg; msg = msg->next) {
		if (strcmp(name, msg->name) == 0) {
			msg->value = value;
			return 0;
		}
	}

	/* Create a new one */
	msg = (UPNP_MSG *)calloc(1, sizeof(*msg));
	if (msg == NULL) {
		upnp_syslog(LOG_ERR, "Out of memory!");
		return -1;
	}

	msg->name = name;
	msg->value = value;

	/* Do prepend */
	msg->next = context->msglist;
	context->msglist = msg;

	return 0;
}
예제 #9
0
int
upnp_device_attach(UPNP_CONTEXT *context, UPNP_DEVICE *device)
{
	UPNP_INTERFACE	*ifp = context->focus_ifp;
	UPNP_DEVCHAIN	*chain;

	upnp_syslog(LOG_INFO, "%s: attach %s", ifp->ifname, device->root_device_xml);

	/* Check if the device has already attached? */
	for (chain = ifp->device_chain;
	     chain;
	     chain = chain->next) {
		/* Attached, do nothing */
		if (chain->device == device)
			return 0;
	}

	/* Allocate a new one */
	chain = (UPNP_DEVCHAIN *)malloc(sizeof(*chain));
	if (chain == 0)
		return -1;

	chain->ifp = ifp;
	chain->device = device;

	/* Prepend this chain */
	chain->next = ifp->device_chain;
	ifp->device_chain = chain;

	ifp->focus_devchain = chain;

	/* Remove this chain, if open error */
	if ((*device->open)(context) != 0) {
		ifp->device_chain = chain->next;
		ifp->focus_devchain = chain->next;

		free(chain);
		return -1;
	}

	/* Initialize gena event variable */
	gena_init(context);

	/* Send byby here */
	ssdp_byebye(context);

	upnp_sleep(1);

	/* Send alive here */
	ssdp_alive(context);

	return 0;
}
예제 #10
0
void
upnp_device_detach(UPNP_CONTEXT *context, UPNP_DEVICE *device)
{
	UPNP_INTERFACE	*ifp = context->focus_ifp;
	UPNP_DEVCHAIN	*chain, *prev;

	upnp_syslog(LOG_INFO, "%s: detach %s", ifp->ifname, device->root_device_xml);

	/* Locate the device chain */
	for (prev = 0, chain = ifp->device_chain;
	     chain;
	     prev = chain, chain = chain->next) {
		if (chain->device == device)
			break;
	}
	if (chain == 0)
		return;

	ifp->focus_devchain = chain;

	/* Do device specific stop function */
	(*device->close)(context);

	/* Clear event variables and subscribers */
	gena_shutdown(context);

	/* Send byebye */
	ssdp_byebye(context);

	/* detach it */
	if (prev == 0)
		ifp->device_chain = chain->next;
	else
		prev->next = chain->next;

	/* Free this chain */
	free(chain);
	return;
}
예제 #11
0
/* Disassemble header and record the message headers */
static int
record_msghdr(UPNP_CONTEXT *context, char *ptr, int eol, int eoh)
{
	int i;

	/* clear end of line characters */
	for (i = 0; i < eol; i++)
		context->buf[context->index-i-1] = 0;

	/* clear end of header characters */
	for (i = 0; i < eoh; i++)
		context->buf[context->index+i] = 0;

	if (context->header_num == MAX_HEADERS) {
		upnp_syslog(LOG_ERR, "Too many header to handle!");
		return -1;
	}

	context->msghdrs[context->header_num] = ptr;
	context->header_num++;
	return 0;
}
예제 #12
0
/* Parse HTTP header and set appropriate env variables */
int
parse_msghdr(UPNP_CONTEXT *context, struct upnp_method *methods)
{
	char *token, *value;
	char *p;
	int i;

	/* skip the first line (method, url, and HTTP version), which we already processed */
	for (i = 1; i < context->header_num; i++) {
		token = context->msghdrs[i];
		strtok_r(token, ":", &value);
		/* skip white spaces */
		while (*token == '\t' || *token == ' ')
			token++;

		if (value != NULL) {
			/* skip white spaces */
			while (*value == '\t' || *value == ' ')
				value++;

			/* capitalize token */
			for (p = token; *p; p++)
				*p = toupper(*p);

			save_header(context, token, value);
		}
		else {
			upnp_syslog(LOG_ERR, "Null value in parse_msghdr()");
			goto error_out;
		}
	}

	return 0;

error_out:
	context->status = R_ERROR;
	return -1;
}
예제 #13
0
/* Process the UPnP request message */
void
upnp_request_handler(UPNP_CONTEXT *context)
{
	int len;
	UPNP_REQUEST *request;
	UPNP_DEVICE *device = 0;
	UPNP_INTERFACE *ifp = context->focus_ifp;
	UPNP_DEVCHAIN *chain;

	/* Read message */
	len = read_request(context);
	if (len <= 0)
		return;

	request = (UPNP_REQUEST *)context->buf;
	if (get_device_from_reqcmd(request->cmd)) {
		int i;

		for (i = 0; (device = upnp_device_table[i]) != 0; i++) {
			if (strcmp(device->root_device_xml, request->url) == 0)
				break;
		}
		if (device == 0)
			return;
	}

	/* Switch the operation */
	switch (request->cmd)
	{
	case UPNP_REQ_DEV_ADD:
		upnp_syslog(LOG_INFO, "UPNP_CMD_DEV_ADD");

		upnp_device_attach(context, device);
		break;

	case UPNP_REQ_DEV_DEL:
		upnp_syslog(LOG_INFO, "UPNP_CMD_DEV_DEL");

		upnp_device_detach(context, device);
		break;

	case UPNP_REQ_GET_STATE_VAR:
		request->status = soap_get_state_var(
				context,
				request->url,
				request->var[0].statevar,
				&request->var[0].value);
		upnp_request_response(context, request);
		break;

	case UPNP_REQ_SET_EVENT_VAR:
		gena_event_alarm(context, request->url, request->num, request->var);
		break;

	case UPNP_REQ_GENA_NOTIFY:
		gena_event_alarm(context, request->url, 0, 0);
		break;

	default:
		upnp_syslog(LOG_INFO, "Device command.");
		for (chain = ifp->device_chain;
			chain;
			chain = chain->next) {
			if (chain->device == device) {
				ifp->focus_devchain = chain;
				device->request(context, request);
				break;
			}
		}
		break;
	}

	return;
}
예제 #14
0
/* Give a unique uuid to this rootdevice */
int
upnp_device_renew_uuid(UPNP_CONTEXT *context, UPNP_DEVICE *device)
{
	char *s, *p;
	char deviceType[256];
	char serviceType[256];
	char new_uuid[64];

	UPNP_DESCRIPTION *desc;

	/* Find root device */
	for (desc = device->description_table; desc; desc++) {
		if (strcmp(device->root_device_xml, desc->name+1) == 0)
			break;
	}
	if (desc == 0) {
		upnp_syslog(LOG_ERR, "Root device can not find it's xml.");
		return -1;
	}

	/*
	 * Update UUID of the root device xml
	 * for each AP/router. By using the MAC address
	 * and the value between <deviceType>...</deviceType>, we can
	 * generate a unique UUID.
	 */
	for (p = desc->xml; *p != 0; p++) {
		/* Search for <deviceType> */
		if (strncmp(p, DEVICE_BTAG, strlen(DEVICE_BTAG)) == 0) {

			p += strlen(DEVICE_BTAG);

			/* Find the balanced </deviceType> */
			s = strstr(p, DEVICE_ETAG);
			if (s == 0 || (s-p) > sizeof(deviceType)-1) {
				upnp_syslog(LOG_ERR,
					"Parse format:<deviceType>...</deviceType> error.\n");
				return -1;
			}

			/* Save deviceType */
			memcpy(deviceType, p, s-p);
			deviceType[s-p] = '\0';
			p = s + strlen(DEVICE_ETAG);
		}

		/*
		 * For example,
		 * <deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
		 * the value between <UDN>...</UDN> is the UUID we have to replace.
		 * The UUID format is such as, uuid:eb9ab5b2-981c-4401-a20e-b7bcde359dbb.
		 * By generate the same UUID size, we don't have to do memory ajustment.
		 */
		if (strncmp(p, UDN_BTAG, strlen(UDN_BTAG)) == 0) {

			p += strlen(UDN_BTAG);

			/* Find the balanced </UDN> */
			s = strstr(p, UDN_ETAG);
			if (s == 0 || (s-p) > sizeof(deviceType)-1) {
				upnp_syslog(LOG_ERR, "Parse format:<UDN>...</UDN> error.\n");
				return -1;
			}

			p += 5; /* "uuid:" is 5 char */
			if ((s-p) != 36) {
				upnp_syslog(LOG_ERR, "UUID length is not 36.\n");
				return -1;
			}

			/* Replace uuid */
			upnp_gen_uuid(new_uuid, deviceType);

			memcpy(p, new_uuid, 36);  /* uuid is 36 characters. */
			p = p + 36;				  /* 46 = 10 + 36 */

			/*
			 * Afert the UUID of device in description XML is changed,
			 * we have to sync this new UUID to the advertisement table.
			 */
			sync_advertise_uuid(device, new_uuid, deviceType);
		}

		/*
		 * The SSDP broadcasts not only the device information but
		 * also all the services of this device, which shares the
		 * UUID of that device.
		 * As a result, we have to find out all the <serviceType>'s
		 * of this <deviceType>, and sync the device UUID to the
		 * advertisement table
		 */
		if (strncmp(p, SERVICE_BTAG, strlen(SERVICE_BTAG)) == 0) {

			p += strlen(SERVICE_BTAG);

			/* Find the balanced </serviceType> */
			s = strstr(p, SERVICE_ETAG);
			if (s == 0 || (s-p) > sizeof(serviceType)-1) {
				upnp_syslog(LOG_ERR,
					"Parse format:<serviceType>...</serviceType> error.\n");
				return -1;
			}

			/* Save serviceType */
			strncpy(serviceType, p, s-p);
			serviceType[s-p] = '\0';
			p = s + strlen(SERVICE_ETAG);

			/*
			 * Found a <serviceType>...</serviceType>.
			 * For example,
			 * <serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1
			 * </serviceType>
			 * is the service of
			 * <deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1
			 * </deviceType>.
			 * We have to search the
			 * "urn:schemas-upnp-org:service:Layer3Forwarding:1"
			 * in the advertisement table, and replace its UUID with the UUID of
			 * "urn:schemas-upnp-org:device:InternetGatewayDevice:1".
			 */
			sync_advertise_uuid(device, new_uuid, serviceType);
		}
	}

	return 0;
}
예제 #15
0
/* UPnP module initialization */
int
upnp_init(UPNP_CONTEXT *context)
{
	UPNP_INTERFACE	*ifp = 0;
	UPNP_DEVICE		*device;
	int	i;

	char ifname_list[256];
	
	
	char *name, *p, *next;

	sprintf(xml_InternetGatewayDevice_real,xml_InternetGatewayDevice,nvram_safe_get("DD_BOARD"),nvram_safe_get("router_name"),nvram_safe_get("DD_BOARD"));
	/* Clear flag */
	upnp_flag = 0;

	/* Clean up */
	memset(context, 0, sizeof(*context));

	upnp_osl_read_config(&context->config);
	oslib_ifname_list(ifname_list);

	/* Do context common initialization */
	context->adv_seconds = time(0);
	context->gena_last_check = time(0);
	context->ssdp_sock = -1;

	for (i = 0; (device = upnp_device_table[i]) != 0; i++) {
		(*device->common_init)(context);

		/*
		 * Give a unique uuid to this router,
		 * create same uuid when restart
		 */
		upnp_device_renew_uuid(context, device);
	}

	/* Create the mutlicast receive socket for all interfaces */
	if (ssdp_init(context) != 0)
		goto error_out;

	for (name = ifname_list, p = name;
	     name && name[0];
	     name = next, p = 0) {
		strtok_r(p, " ", &next);

		ifp = upnp_ifinit(context, name);
		if (ifp == 0)
			continue;

		context->focus_ifp = ifp;

		/* Perform per interface protocol initialization */
		if (upnp_http_init(context) != 0) {
			upnp_syslog(LOG_ERR, "upnp_http_init::%s init error!", ifp->ifname);
			goto error_out;
		}

		if (ssdp_add_multi(context) == -1) {
			upnp_syslog(LOG_ERR, "ssdp_init::%s error!", ifp->ifname);
			goto error_out;
		}

		if (upnp_request_init(context) != 0) {
			upnp_syslog(LOG_ERR, "upnp_request_init::init error!");
			goto error_out;
		}

		/*
		 * Hook device table to each interface.
		 * The init function of each device
		 * intialize the event variables, and send SSDP ALIVE to each
		 * interface
		 */
		for (i = 0; (device = upnp_device_table[i]) != 0; i++) {
			if (device->attach_mode == DEVICE_ATTACH_ALWAYS)
				upnp_device_attach(context, device);
		}
	}

	/* No interface found, return directly */
	if (context->iflist == 0) {
		upnp_syslog(LOG_ERR, "No UPnP interface specified, bye!");
		goto error_out;
	}

	upnp_syslog(LOG_INFO, "UPnP daemon is ready to run");
	return 0;

error_out:
	upnp_flag = UPNP_FLAG_SHUTDOWN;
	return -1;
}