コード例 #1
0
ファイル: plugtest-server.c プロジェクト: robbie-cao/smcp
smcp_status_t
plugtest_separate_handler(
	smcp_node_t		node
) {
	struct smcp_async_response_s* async_response = NULL;
	smcp_transaction_t transaction = NULL;
	smcp_status_t ret = SMCP_STATUS_NOT_ALLOWED;
	smcp_method_t method = smcp_inbound_get_code();

	if(method==COAP_METHOD_GET) {
		if(smcp_inbound_is_dupe()) {
			smcp_outbound_begin_response(COAP_CODE_EMPTY);
			smcp_outbound_send();
			ret = SMCP_STATUS_OK;
			goto bail;
		}

		async_response = calloc(sizeof(struct smcp_async_response_s),1);
		if(!async_response) {
			ret = SMCP_STATUS_MALLOC_FAILURE;
			goto bail;
		}

#if !SMCP_AVOID_PRINTF || VERBOSE_DEBUG
		printf("This request needs an async response. %p\n",async_response);
#endif

		transaction = smcp_transaction_init(
			NULL,
			SMCP_TRANSACTION_DELAY_START|SMCP_TRANSACTION_ALWAYS_INVALIDATE,
			&plugtest_separate_async_resend_response,
			&plugtest_separate_async_ack_handler,
			(void*)async_response
		);
		if(!transaction) {
			free(async_response);
			// TODO: Consider dropping instead...?
			ret = SMCP_STATUS_MALLOC_FAILURE;
			goto bail;
		}

		ret = smcp_transaction_begin(
			smcp_get_current_instance(),
			transaction,
			(smcp_inbound_get_packet()->tt==COAP_TRANS_TYPE_CONFIRMABLE)?(smcp_cms_t)(COAP_MAX_TRANSMIT_WAIT*MSEC_PER_SEC):1
		);
		if(SMCP_STATUS_OK != ret) {
			smcp_transaction_end(smcp_get_current_instance(),transaction);
			goto bail;
		}

		ret = smcp_start_async_response(async_response,0);
		if(ret) { goto bail; }

		async_response = NULL;
	}

bail:
	return ret;
}
コード例 #2
0
ファイル: cmd_test.c プロジェクト: ndaskalov-mms/smcp
smcp_status_t
async_request_handler(
	smcp_node_t		node
) {
	smcp_status_t ret = SMCP_STATUS_OK;
	smcp_method_t	method = smcp_inbound_get_code();
	if(method==COAP_METHOD_GET) {
		ret = smcp_start_async_response(&async_response,0);
		if(ret==SMCP_STATUS_DUPE) {
			printf("  ** Dupe, already preparing async response.\n");
		} else if(!ret) {
			printf(" *** Request requires an async response...!\n");
		}
		require_noerr(ret, bail);

		ret = smcp_begin_transaction_old(
			smcp_get_current_instance(),
			smcp_get_next_msg_id(smcp_get_current_instance()),
			30*1000,	// Retry for thirty seconds.
			SMCP_TRANSACTION_DELAY_START, // Flags
			(void*)&resend_async_response,
			(void*)&async_response_ack_handler,
			(void*)&async_response
		);
	} else {
		ret = SMCP_STATUS_NOT_ALLOWED;
	}

bail:
	return ret;
}
コード例 #3
0
ファイル: smcp-observable.c プロジェクト: errordeveloper/smcp
smcp_status_t
smcp_observable_update(smcp_observable_t context, uint8_t key) {
	smcp_status_t ret = SMCP_STATUS_OK;
	smcp_t const interface = smcp_get_current_instance();
	int8_t i;

#if !SMCP_EMBEDDED
	context->interface = interface;
#endif

	if(interface->inbound.is_fake || interface->inbound.is_dupe) {
		goto bail;
	}

	for(i = context->first_observer-1; i >= 0; i = observer_table[i].next - 1) {
		if(observer_table[i].key != key)
			continue;
		if(smcp_inbound_is_related_to_async_response(&observer_table[i].async_response))
			break;
	}

	if(interface->inbound.has_observe_option) {
		if(i == -1) {
			i = get_unused_observer_index();
			if(i == -1)
				goto bail;
			if(context->last_observer == 0) {
				context->first_observer = context->last_observer = i + 1;
			} else {
				observer_table[context->last_observer-1].next = i +1;
				context->last_observer = i + 1;
			}
			observer_table[i].key = key;
			observer_table[i].seq = 0;
			observer_table[i].observable = context;
		}

		smcp_start_async_response(&observer_table[i].async_response,SMCP_ASYNC_RESPONSE_FLAG_DONT_ACK);

		ret = smcp_outbound_add_option_uint(COAP_OPTION_OBSERVE,observer_table[i].seq);
	} else if(i != -1) {
		free_observer(&observer_table[i]);
	}

bail:
	return ret;
}
コード例 #4
0
ファイル: smcp-curl_proxy.c プロジェクト: sandy7de/smcp
smcp_status_t
smcp_curl_proxy_request_handler(
    smcp_curl_proxy_node_t		node
) {
    smcp_status_t ret = SMCP_STATUS_NOT_ALLOWED;
    smcp_curl_request_t request = NULL;
    struct curl_slist *headerlist=NULL;
    smcp_method_t method = smcp_inbound_get_code();

    //require_action(method<=COAP_METHOD_DELETE,bail,ret = SMCP_STATUS_NOT_ALLOWED);

    //require_action(COAP_OPTION_URI_PATH!=smcp_inbound_peek_option(NULL,NULL),bail,ret=SMCP_STATUS_NOT_FOUND);

    node->interface = smcp_get_current_instance();

    smcp_inbound_reset_next_option();

    request = smcp_curl_request_create();
    request->proxy_node = node;

    require_action(request!=NULL,bail,ret = SMCP_STATUS_MALLOC_FAILURE);

    switch(method) {
    case COAP_METHOD_GET:
        curl_easy_setopt(request->curl, CURLOPT_CUSTOMREQUEST, "GET");
        break;
    case COAP_METHOD_PUT:
        curl_easy_setopt(request->curl, CURLOPT_PUT, 1L);
        break;
    case COAP_METHOD_POST:
        curl_easy_setopt(request->curl, CURLOPT_POST, 1L);
        break;
    case COAP_METHOD_DELETE:
        curl_easy_setopt(request->curl, CURLOPT_CUSTOMREQUEST, "DELETE");
        break;
    default:
        ret = SMCP_STATUS_NOT_ALLOWED;
        break;
    }

    {
        coap_option_key_t key;
        const uint8_t* value;
        coap_size_t value_len;
        while((key=smcp_inbound_next_option(&value, &value_len))!=COAP_OPTION_INVALID) {
            if(key==COAP_OPTION_PROXY_URI) {
                char uri[value_len+1];
                memcpy(uri,value,value_len);
                uri[value_len] = 0;
                curl_easy_setopt(request->curl, CURLOPT_URL, uri);
                assert_printf("CuRL URL: \"%s\"",uri);
                ret = 0;
            } else if(key==COAP_OPTION_URI_HOST) {
            } else if(key==COAP_OPTION_URI_PORT) {
            } else if(key==COAP_OPTION_URI_PATH) {
            } else if(key==COAP_OPTION_URI_QUERY) {
            } else if(key==COAP_OPTION_CONTENT_TYPE || key==COAP_OPTION_ACCEPT) {
                const char* option_name = coap_option_key_to_cstr(key, false);
                const char* value_string = coap_content_type_to_cstr(value[1]);
                char header[strlen(option_name)+strlen(value_string)+3];
                strcpy(header,option_name);
                strcat(header,": ");
                strcat(header,value_string);
                headerlist = curl_slist_append(headerlist, header);
                assert_printf("CuRL HEADER: \"%s\"",header);
            } else {
                if(coap_option_value_is_string(key)) {
                    const char* option_name = coap_option_key_to_cstr(key, false);
                    char header[strlen(option_name)+value_len+3];
                    strcpy(header,option_name);
                    strcat(header,": ");
                    strncat(header,(const char*)value,value_len);
                    assert_printf("CuRL HEADER: \"%s\"",header);
                    headerlist = curl_slist_append(headerlist, header);
                }
            }
        }
    }

    require_noerr(ret,bail);

    if(smcp_inbound_get_content_len()) {
        coap_size_t len = smcp_inbound_get_content_len();
        request->output_content = calloc(1,len+1);
        request->output_content_len = len;
        memcpy(request->output_content,smcp_inbound_get_content_ptr(),len);
        curl_easy_setopt(request->curl, CURLOPT_READFUNCTION, ReadMemoryCallback);
        curl_easy_setopt(request->curl, CURLOPT_READDATA, (void *)request);
    }

    curl_easy_setopt(request->curl, CURLOPT_USERAGENT, "smcp-curl-proxy/1.0");
    curl_easy_setopt(request->curl, CURLOPT_HTTPHEADER, headerlist),headerlist=NULL;
    curl_easy_setopt(request->curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(request->curl, CURLOPT_WRITEDATA, (void *)request);

    ret = smcp_start_async_response(&request->async_response,0);
    require_noerr(ret,bail);

    if(node->curl_multi_handle)
        curl_multi_add_handle(node->curl_multi_handle, request->curl);
    else
        curl_easy_perform(request->curl);

bail:
    if(headerlist)
        curl_slist_free_all(headerlist);

    if(ret && request)
        smcp_curl_request_release(request);

    return ret;
}
コード例 #5
0
ファイル: cgi-node.c プロジェクト: robbie-cao/smcp
smcp_status_t
cgi_node_request_change_state(cgi_node_t node, cgi_node_request_t request, cgi_node_state_t new_state) {
	// TODO: Possibly do more later...?

	syslog(LOG_INFO, "cgi-node: %d -> %d", request->state, new_state);

	if(request->state == new_state) {
		// Same state, do nothing.
	} else

	if ( request->state == CGI_NODE_STATE_INACTIVE
	  && new_state == CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_REQ
	) {

	} else if ( request->state == CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_REQ
	         && new_state == CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_FD
	) {
		smcp_start_async_response(&request->async_response, 0);

	} else if ( request->state == CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_FD
	         && new_state == CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_ACK
	) {
		cgi_node_send_next_block(node,request);

	} else if ( request->state == CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_ACK
	         && new_state == CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_REQ
	) {
		if (request->transaction) {
			smcp_transaction_end(smcp_get_current_instance(),request->transaction);
			request->transaction = NULL;
		}

	} else if ( ( (request->state == CGI_NODE_STATE_ACTIVE_BLOCK2_WAIT_REQ)
	           || (request->state == CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_REQ)
	            )
	         && ( new_state == CGI_NODE_STATE_ACTIVE_BLOCK2_WAIT_FD)
	) {
		if(!request->stdin_buffer_len &&  request->fd_cmd_stdin>=0) {
			close(request->fd_cmd_stdin);
			request->fd_cmd_stdin = -1;
		}
		smcp_start_async_response(&request->async_response, 0);
	} else if(request->state == CGI_NODE_STATE_ACTIVE_BLOCK2_WAIT_FD
		&& new_state == CGI_NODE_STATE_ACTIVE_BLOCK2_WAIT_ACK
	) {
		if(!request->stdin_buffer_len &&  request->fd_cmd_stdin>=0) {
			close(request->fd_cmd_stdin);
			request->fd_cmd_stdin = -1;
		}
		cgi_node_send_next_block(node,request);
	} else if(request->state == CGI_NODE_STATE_ACTIVE_BLOCK2_WAIT_ACK
		&& new_state == CGI_NODE_STATE_ACTIVE_BLOCK2_WAIT_REQ
	) {
		if(!request->stdin_buffer_len &&  request->fd_cmd_stdin>=0) {
			close(request->fd_cmd_stdin);
			request->fd_cmd_stdin = -1;
		}
		//cgi_node_request_pop_bytes_from_stdout(request,(1<<((request->block2&0x7)+4)));
		if(request->transaction) {
			smcp_transaction_end(smcp_get_current_instance(),request->transaction);
			request->transaction = NULL;
		}
	} else if(new_state == CGI_NODE_STATE_FINISHED) {
		if(request->transaction) {
			smcp_transaction_end(smcp_get_current_instance(),request->transaction);
			request->transaction = NULL;
		}
		close(request->fd_cmd_stdin);
		request->fd_cmd_stdin = -1;
		close(request->fd_cmd_stdout);
		request->fd_cmd_stdout = -1;
		if(request->pid != 0 && request->pid != -1) {
			int status;
			kill(request->pid,SIGTERM);
			if(waitpid(request->pid, &status, WNOHANG) == request->pid) {
				request->pid = 0;
			}
		}
	} else {
		// INVALID STATE TRANSITION!
		syslog(LOG_ERR, "cgi-node: BAD STATE CHANGE: %d -> %d", request->state, new_state);
		abort();
	}

	request->state = new_state;

	return SMCP_STATUS_OK;
}
コード例 #6
0
ファイル: cgi-node.c プロジェクト: robbie-cao/smcp
cgi_node_request_t
cgi_node_create_request(cgi_node_t node) {
	cgi_node_request_t ret = NULL;
	int i;
	int pipe_cmd_stdin[2];
	int pipe_cmd_stdout[2];

	for (i=0; i < CGI_NODE_MAX_REQUESTS; i++) {
		if (node->requests[i].state <= CGI_NODE_STATE_FINISHED) {
			ret = &node->requests[i];
			if (node->requests[i].state == CGI_NODE_STATE_INACTIVE) {
				break;
			}
		}
	}

	require(ret,bail);

	ret->is_active = 1;
	ret->state = CGI_NODE_STATE_ACTIVE_BLOCK1_WAIT_REQ;

	if(ret->pid != 0 && ret->pid != -1) {
		int status;
		kill(ret->pid,SIGKILL);
		waitpid(ret->pid, &status, 0);
	}

	if(ret->fd_cmd_stdin>=0) {
		close(ret->fd_cmd_stdin);
	}

	if(ret->fd_cmd_stdout>=0) {
		close(ret->fd_cmd_stdout);
	}

	ret->pid = 0;
	ret->fd_cmd_stdin = -1;
	ret->fd_cmd_stdout = -1;
	ret->block1 = BLOCK_OPTION_UNSPECIFIED;
	ret->block2 = BLOCK_OPTION_DEFAULT; // Default value, overwrite with actual block
	ret->stdin_buffer_len = 0;
	ret->stdout_buffer_len = 0;
	ret->expiration = smcp_plat_cms_to_timestamp(30 * MSEC_PER_SEC);

	free(ret->stdin_buffer);
	ret->stdin_buffer = NULL;

	free(ret->stdout_buffer);
	ret->stdout_buffer = NULL;

	smcp_start_async_response(&ret->async_response, SMCP_ASYNC_RESPONSE_FLAG_DONT_ACK);

	pipe(pipe_cmd_stdin);
	pipe(pipe_cmd_stdout);

	if(!(ret->pid=fork())) {
		// We are the child!
		char path[2048]; // todo: this max should be a preprocessor macro

		// Update stdin and stdout.
		dup2(pipe_cmd_stdin[0],STDIN_FILENO);
		dup2(pipe_cmd_stdout[1],STDOUT_FILENO);

		close(pipe_cmd_stdin[0]);
		close(pipe_cmd_stdin[1]);
		close(pipe_cmd_stdout[0]);
		close(pipe_cmd_stdout[1]);

		path[0] = 0;
		smcp_node_get_path(&node->node,path,sizeof(path));
		setenv("SCRIPT_NAME",path,1);

		setenv("SERVER_SOFTWARE","smcpd/"PACKAGE_VERSION,1);
		setenv("REQUEST_METHOD",coap_code_to_cstr(smcp_inbound_get_packet()->code),1);
		setenv("REQUEST_URI",smcp_inbound_get_path(path,2),1);
		setenv("GATEWAY_INTERFACE","CGI/1.1",1);
		setenv("SERVER_PROTOCOL","CoAP/1.0",1);

		setenv("REMOTE_ADDR","",1);
		setenv("REMOTE_PORT","",1);
		setenv("SERVER_NAME","",1);
		setenv("SERVER_ADDR","",1);
		setenv("SERVER_PORT","",1);

		if (0 == strncmp(path,getenv("SCRIPT_NAME"),strlen(getenv("SCRIPT_NAME")))) {
			setenv("PATH_INFO",path+strlen(getenv("SCRIPT_NAME")),1);
		}

		syslog(LOG_DEBUG, "cgi-node: About to execute \"%s\" using shell \"%s\"", node->cmd, node->shell);

		execl(node->shell,node->shell,"-c",node->cmd,NULL);

		syslog(LOG_ERR, "cgi-node: Failed to execute \"%s\" using shell \"%s\"", node->cmd, node->shell);

		// We should never get here...
		abort();
	}

	if (ret->pid < 0) {
		// Oh hell.

		syslog(LOG_ERR,"Unable to fork!");

		close(pipe_cmd_stdin[0]);
		close(pipe_cmd_stdin[1]);
		close(pipe_cmd_stdout[0]);
		close(pipe_cmd_stdout[1]);

		ret->is_active = 0;
		ret->state = CGI_NODE_STATE_INACTIVE;

		ret = NULL;
		goto bail;
	}

	ret->fd_cmd_stdin = pipe_cmd_stdin[1];
	ret->fd_cmd_stdout = pipe_cmd_stdout[0];

	close(pipe_cmd_stdin[0]);
	close(pipe_cmd_stdout[1]);

bail:
	return ret;
}