diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index 871ec2bfe..55cdbacbd 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -1442,6 +1442,7 @@ enum TALER_ErrorCode * The amount to be refunded is inconsistent: either is lower than * the previous amount being awarded, or it is too big to be paid back. * In this second case, the fault stays on the business dept. side. + * Returned with an HTTP status of #MHD_HTTP_CONFLICT. */ TALER_EC_REFUND_INCONSISTENT_AMOUNT = 2602, diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index 17783f1c4..cdbc8d290 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -143,6 +143,40 @@ TALER_MHD_reply_with_error (struct MHD_Connection *connection, const char *hint); +/** + * Make JSON response object. + * + * @param json the json object + * @return MHD response object + */ +struct MHD_Response * +TALER_MHD_make_json (const json_t *json); + + +/** + * Make JSON response object. + * + * @param fmt format string for pack + * @param ... varargs + * @return MHD response object + */ +struct MHD_Response * +TALER_MHD_make_json_pack (const char *fmt, + ...); + + +/** + * Create a response indicating an internal error. + * + * @param ec error code to return + * @param hint hint about the internal error's nature + * @return a MHD response object + */ +struct MHD_Response * +TALER_MHD_make_error (enum TALER_ErrorCode ec, + const char *hint); + + /** * Send a response indicating that the request was too big. * @@ -338,4 +372,22 @@ TALER_MHD_open_unix_path (const char *unix_path, mode_t unix_mode); +/** + * Bind a listen socket to the UNIX domain path + * or the TCP port and IP address as specified + * in @a cfg in section @a section. IF only a + * port was specified, set @a port and return -1. + * Otherwise, return the bound file descriptor. + * + * @param cfg configuration to parse + * @param section configuration section to use + * @param port[out] port to set, if TCP without BINDTO + * @return -1 and a port of zero on error, otherwise + * either -1 and a port, or a bound stream socket + */ +int +TALER_MHD_bind (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + uint16_t *port); + #endif diff --git a/src/mhd/mhd_config.c b/src/mhd/mhd_config.c index afaceae40..d4b0e9795 100644 --- a/src/mhd/mhd_config.c +++ b/src/mhd/mhd_config.c @@ -285,3 +285,112 @@ TALER_MHD_open_unix_path (const char *unix_path, GNUNET_NETWORK_socket_free_memory_only_ (nh); return fd; } + + +/** + * Bind a listen socket to the UNIX domain path + * or the TCP port and IP address as specified + * in @a cfg in section @a section. IF only a + * port was specified, set @a port and return -1. + * Otherwise, return the bound file descriptor. + * + * @param cfg configuration to parse + * @param section configuration section to use + * @param port[out] port to set, if TCP without BINDTO + * @return -1 and a port of zero on error, otherwise + * either -1 and a port, or a bound stream socket + */ +int +TALER_MHD_bind (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + uint16_t *port) +{ + char *bind_to; + char *serve_unixpath; + mode_t unixpath_mode; + int fh; + char port_str[6]; + struct addrinfo hints; + struct addrinfo *res; + int ec; + struct GNUNET_NETWORK_Handle *nh; + + *port = 0; + if (GNUNET_OK != + TALER_MHD_parse_config (cfg, + section, + port, + &serve_unixpath, + &unixpath_mode)) + return -1; + if (NULL != serve_unixpath) + return TALER_MHD_open_unix_path (serve_unixpath, + unixpath_mode); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + section, + "BIND_TO", + &bind_to)) + return -1; /* only set port */ + /* let's have fun binding... */ + GNUNET_snprintf (port_str, + sizeof (port_str), + "%u", + (unsigned int) *port); + *port = 0; /* do NOT return port in case of errors */ + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE +#ifdef AI_IDN + | AI_IDN +#endif + ; + if (0 != + (ec = getaddrinfo (bind_to, + port_str, + &hints, + &res))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to resolve BIND_TO address `%s': %s\n", + bind_to, gai_strerror (ec)); + GNUNET_free (bind_to); + return -1; + } + GNUNET_free (bind_to); + + if (NULL == (nh = GNUNET_NETWORK_socket_create (res->ai_family, + res->ai_socktype, + res->ai_protocol))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "socket"); + freeaddrinfo (res); + return -1; + } + if (GNUNET_OK != + GNUNET_NETWORK_socket_bind (nh, + res->ai_addr, + res->ai_addrlen)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "bind"); + freeaddrinfo (res); + return -1; + } + freeaddrinfo (res); + if (GNUNET_OK != + GNUNET_NETWORK_socket_listen (nh, + UNIX_BACKLOG)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "listen"); + GNUNET_SCHEDULER_shutdown (); + return -1; + } + fh = GNUNET_NETWORK_get_fd (nh); + GNUNET_NETWORK_socket_free_memory_only_ (nh); + return fh; +} diff --git a/src/mhd/mhd_responses.c b/src/mhd/mhd_responses.c index e1609d996..3642e7d54 100644 --- a/src/mhd/mhd_responses.c +++ b/src/mhd/mhd_responses.c @@ -151,6 +151,43 @@ TALER_MHD_body_compress (void **buf, } +/** + * Make JSON response object. + * + * @param json the json object + * @return MHD response object + */ +struct MHD_Response * +TALER_MHD_make_json (const json_t *json) +{ + struct MHD_Response *resp; + char *json_str; + + json_str = json_dumps (json, + JSON_INDENT (2)); + if (NULL == json_str) + { + GNUNET_break (0); + return NULL; + } + resp = MHD_create_response_from_buffer (strlen (json_str), + json_str, + MHD_RESPMEM_MUST_FREE); + if (NULL == resp) + { + free (json_str); + GNUNET_break (0); + return NULL; + } + TALER_MHD_add_global_headers (resp); + GNUNET_break (MHD_YES == + MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json")); + return resp; +} + + /** * Send JSON object as response. * @@ -267,6 +304,60 @@ TALER_MHD_reply_json_pack (struct MHD_Connection *connection, } +/** + * Make JSON response object. + * + * @param fmt format string for pack + * @param ... varargs + * @return MHD response object + */ +struct MHD_Response * +TALER_MHD_make_json_pack (const char *fmt, + ...) +{ + json_t *json; + va_list argp; + struct MHD_Response *ret; + json_error_t jerror; + + va_start (argp, fmt); + json = json_vpack_ex (&jerror, + 0, + fmt, + argp); + va_end (argp); + if (NULL == json) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to pack JSON with format `%s': %s\n", + fmt, + jerror.text); + GNUNET_break (0); + return MHD_NO; + } + ret = TALER_MHD_make_json (json); + json_decref (json); + return ret; +} + + +/** + * Create a response indicating an internal error. + * + * @param ec error code to return + * @param hint hint about the internal error's nature + * @return a MHD response object + */ +struct MHD_Response * +TALER_MHD_make_error (enum TALER_ErrorCode ec, + const char *hint) +{ + return TALER_MHD_make_json_pack ("{s:I, s:s}", + "code", (json_int_t) ec, + "hint", hint); +} + + /** * Send a response indicating an error. *