gboolean xr_server_register_servlet(xr_server* server, xr_servlet_def* servlet) { xr_trace(XR_DEBUG_SERVER_TRACE, "(server=%p, servlet=%p)", server, servlet); g_return_val_if_fail(server != NULL, FALSE); g_return_val_if_fail(servlet != NULL, FALSE); if (_find_servlet_def(server, servlet->name)) return FALSE; server->servlet_types = g_slist_append(server->servlet_types, servlet); return TRUE; }
gboolean xr_client_open(xr_client_conn* conn, const char* uri, GError** err) { GError* local_err = NULL; g_return_val_if_fail(conn != NULL, FALSE); g_return_val_if_fail(uri != NULL, FALSE); g_return_val_if_fail(!conn->is_open, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); xr_trace(XR_DEBUG_CLIENT_TRACE, "(conn=%p, uri=%s)", conn, uri); // parse URI format: http://host:8080/RES g_free(conn->host); g_free(conn->resource); conn->host = NULL; conn->resource = NULL; if (!_parse_uri(uri, &conn->secure, &conn->host, &conn->resource)) { g_set_error(err, XR_CLIENT_ERROR, XR_CLIENT_ERROR_FAILED, "invalid URI format: %s", uri); return FALSE; } // enable/disable TLS if (conn->secure) { g_socket_client_set_tls(conn->client, TRUE); g_socket_client_set_tls_validation_flags(conn->client, G_TLS_CERTIFICATE_VALIDATE_ALL & ~G_TLS_CERTIFICATE_UNKNOWN_CA & ~G_TLS_CERTIFICATE_BAD_IDENTITY); } else { g_socket_client_set_tls(conn->client, FALSE); } conn->conn = g_socket_client_connect_to_host(conn->client, conn->host, 80, NULL, &local_err); if (local_err) { g_propagate_prefixed_error(err, local_err, "Connection failed: "); return FALSE; } xr_set_nodelay(g_socket_connection_get_socket(conn->conn)); conn->http = xr_http_new(G_IO_STREAM(conn->conn)); g_free(conn->session_id); conn->session_id = g_strdup_printf("%08x%08x%08x%08x", g_random_int(), g_random_int(), g_random_int(), g_random_int()); conn->is_open = 1; xr_client_set_http_header(conn, "X-SESSION-ID", conn->session_id); return TRUE; }
void xr_client_free(xr_client_conn* conn) { xr_trace(XR_DEBUG_CLIENT_TRACE, "(conn=%p)", conn); if (conn == NULL) return; xr_client_close(conn); g_free(conn->host); g_free(conn->resource); g_free(conn->session_id); g_hash_table_destroy(conn->headers); g_free(conn); }
gboolean xr_server_run(xr_server* server, GError** err) { GError* local_err = NULL; xr_trace(XR_DEBUG_SERVER_TRACE, "(server=%p, err=%p)", server, err); g_return_val_if_fail(server != NULL, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); g_socket_service_start(G_SOCKET_SERVICE(server->service)); server->loop = g_main_loop_new(NULL, TRUE); g_main_loop_run(server->loop); return TRUE; }
xr_client_conn* xr_client_new(GError** err) { g_return_val_if_fail(err == NULL || *err == NULL, NULL); xr_trace(XR_DEBUG_CLIENT_TRACE, "(err=%p)", err); xr_init(); xr_client_conn* conn = g_new0(xr_client_conn, 1); conn->client = g_socket_client_new(); conn->headers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); conn->transport = XR_CALL_XML_RPC; return conn; }
void xr_client_close(xr_client_conn* conn) { xr_trace(XR_DEBUG_CLIENT_TRACE, "(conn=%p)", conn); g_return_if_fail(conn != NULL); if (!conn->is_open) return; xr_http_free(conn->http); conn->http = NULL; if (conn->conn) g_object_unref(conn->conn); conn->conn = NULL; conn->is_open = FALSE; }
void xr_server_free(xr_server* server) { xr_trace(XR_DEBUG_SERVER_TRACE, "(server=%p)", server); if (server == NULL) return; if (server->cert) g_object_unref(server->cert); g_object_unref(server->service); g_slist_free(server->servlet_types); g_thread_join(server->sessions_cleaner); g_hash_table_destroy(server->sessions); g_static_rw_lock_free(&server->sessions_lock); g_main_loop_unref(server->loop); g_free(server); }
xr_server* xr_server_new(const char* cert, const char* privkey, int threads, GError** err) { xr_trace(XR_DEBUG_SERVER_TRACE, "(cert=%s, threads=%d, err=%p)", cert, threads, err); GError* local_err = NULL; g_return_val_if_fail(threads > 0 && threads < 1000, NULL); g_return_val_if_fail (err == NULL || *err == NULL, NULL); xr_init(); xr_server* server = g_new0(xr_server, 1); server->secure = !!cert; server->service = g_threaded_socket_service_new(threads); g_signal_connect(server->service, "run", (GCallback)_xr_server_service_run, server); if (cert) { gchar *cert_and_privkey = g_strconcat(cert, privkey, NULL); server->cert = g_tls_certificate_new_from_pem(cert_and_privkey, -1, &local_err); g_free(cert_and_privkey); if (local_err) { g_propagate_prefixed_error(err, local_err, "Certificate load failed: "); goto err0; } } server->sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)xr_servlet_free_fini); g_static_rw_lock_init(&server->sessions_lock); server->sessions_cleaner = g_thread_create((GThreadFunc)sessions_cleaner_func, server, TRUE, NULL); if (server->sessions_cleaner == NULL) goto err1; return server; err1: g_hash_table_destroy(server->sessions); g_static_rw_lock_free(&server->sessions_lock); if (server->cert) g_object_unref(server->cert); err0: g_object_unref(server->service); g_free(server); return NULL; }
gboolean xr_server_bind(xr_server* server, const char* bind_addr, GError** err) { GError* local_err = NULL; char* addr = NULL; int port = 0; xr_trace(XR_DEBUG_SERVER_TRACE, "(server=%p, bind_addr=%s, err=%p)", server, bind_addr, err); g_return_val_if_fail(server != NULL, FALSE); g_return_val_if_fail(bind_addr != NULL, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); g_return_val_if_fail(_parse_addr(bind_addr, &addr, &port), FALSE); if (addr[0] == '*') { g_socket_listener_add_inet_port(G_SOCKET_LISTENER(server->service), (guint16)port, NULL, &local_err); } else { // build address GInetAddress* iaddr = g_inet_address_new_from_string(addr); if (!iaddr) { g_error_new(XR_SERVER_ERROR, XR_SERVER_ERROR_FAILED, "Invalid address: %s", bind_addr); g_free(addr); xr_server_stop(server); return FALSE; } GSocketAddress* isaddr = g_inet_socket_address_new(iaddr, (guint16)port); g_socket_listener_add_address(G_SOCKET_LISTENER(server->service), isaddr, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL, NULL, &local_err); } g_free(addr); if (local_err) { g_propagate_prefixed_error(err, local_err, "Port listen failed: "); xr_server_stop(server); return FALSE; } return TRUE; }
static gboolean _xr_server_serve_request(xr_server* server, xr_server_conn* conn) { const char* method; int version; xr_trace(XR_DEBUG_SERVER_TRACE, "(server=%p, conn=%p)", server, conn); g_return_val_if_fail(server != NULL, FALSE); g_return_val_if_fail(conn != NULL, FALSE); if (!g_socket_connection_is_connected(conn->conn)) return FALSE; /* receive HTTP request */ if (!xr_http_read_header(conn->http, NULL)) return FALSE; /* check if some dumb bunny sent us wrong message type */ if (xr_http_get_message_type(conn->http) != XR_HTTP_REQUEST) return FALSE; method = xr_http_get_method(conn->http); if (method == NULL) return FALSE; version = xr_http_get_version(conn->http); if (!strcmp(method, "GET")) return _xr_server_serve_download(server, conn) && (version == 1); else if (!strcmp(method, "POST")) { int transport = _ctype_to_transport(xr_http_get_header(conn->http, "Content-Type")); if (transport >= 0) { xr_call* call; GString* request; char* buffer; int length; gboolean rs; request = xr_http_read_all(conn->http, NULL); if (request == NULL) return FALSE; /* parse request data into xr_call */ call = xr_call_new(NULL); xr_call_set_transport(call, transport); rs = xr_call_unserialize_request(call, request->str, request->len); g_string_free(request, TRUE); /* run call */ if (!rs) xr_call_set_error(call, -1, "Unserialize request failure."); else _xr_server_servlet_method_call(server, conn, call); /* generate response data from xr_call */ xr_call_serialize_response(call, &buffer, &length); if (xr_debug_enabled & XR_DEBUG_CALL) xr_call_dump(call, 0); /* send HTTP response */ xr_http_setup_response(conn->http, 200); xr_http_set_message_length(conn->http, length); rs = xr_http_write_all(conn->http, buffer, length, NULL); xr_call_free_buffer(call, buffer); xr_call_free(call); return rs && (version == 1); } else return _xr_server_serve_upload(server, conn) && (version == 1); } else return FALSE; return TRUE; }
gboolean xr_client_call(xr_client_conn* conn, xr_call* call, GError** err) { char* buffer; int length; gboolean rs; gboolean write_success; GString* response; xr_trace(XR_DEBUG_CLIENT_TRACE, "(conn=%p, call=%p)", conn, call); g_return_val_if_fail(conn != NULL, FALSE); g_return_val_if_fail(call != NULL, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); if (!conn->is_open) { g_set_error(err, XR_CLIENT_ERROR, XR_CLIENT_ERROR_CLOSED, "Can't perform RPC on closed connection."); return FALSE; } /* serialize nad send XML-RPC request */ xr_call_set_transport(call, conn->transport); xr_call_serialize_request(call, &buffer, &length); xr_http_setup_request(conn->http, "POST", conn->resource, conn->host); g_hash_table_foreach(conn->headers, (GHFunc)_add_http_header, conn->http); if (conn->transport == XR_CALL_XML_RPC) xr_http_set_header(conn->http, "Content-Type", "text/xml"); #ifdef XR_JSON_ENABLED else if (conn->transport == XR_CALL_JSON_RPC) xr_http_set_header(conn->http, "Content-Type", "text/json"); #endif xr_http_set_message_length(conn->http, length); write_success = xr_http_write_all(conn->http, buffer, length, err); xr_call_free_buffer(call, buffer); if (!write_success) { xr_client_close(conn); return FALSE; } /* receive HTTP response header */ if (!xr_http_read_header(conn->http, err)) return FALSE; /* check if some dumb bunny sent us wrong message type */ if (xr_http_get_message_type(conn->http) != XR_HTTP_RESPONSE) return FALSE; response = xr_http_read_all(conn->http, err); if (response == NULL) { xr_client_close(conn); return FALSE; } rs = xr_call_unserialize_response(call, response->str, response->len); g_string_free(response, TRUE); if (!rs) { g_set_error(err, 0, xr_call_get_error_code(call), "%s", xr_call_get_error_message(call)); if (xr_debug_enabled & XR_DEBUG_CALL) xr_call_dump(call, 0); return FALSE; } if (xr_debug_enabled & XR_DEBUG_CALL) xr_call_dump(call, 0); return TRUE; }
void xr_server_stop(xr_server* server) { xr_trace(XR_DEBUG_SERVER_TRACE, "(server=%p)", server); g_return_if_fail(server != NULL); g_socket_service_stop(G_SOCKET_SERVICE(server->service)); g_main_loop_quit(server->loop); }