Fix compiler errors

This commit is contained in:
2025-07-20 21:19:58 +02:00
parent 01bf34b58d
commit 3201eac013
29 changed files with 177 additions and 94 deletions
+17 -1
View File
@@ -6,10 +6,26 @@ LFLAGS = -lssl -lcrypto
CFILES = $(shell find src -name "*.c")
HFILES = $(shell find src -name "*.h")
all: chttp.c chttp.h
EXAMPLES_CLIENT := $(basename $(shell ls examples/client/*.c 2>/dev/null))
EXAMPLES_SERVER := $(basename $(shell ls examples/server/*.c 2>/dev/null))
EXAMPLES_ENGINE := $(basename $(shell ls examples/engine/*.c 2>/dev/null))
all: chttp.c chttp.h examples
chttp.c chttp.h: $(HFILES) $(CFILES)
python misc/amalg.py
examples: $(EXAMPLES_CLIENT) $(EXAMPLES_SERVER) $(EXAMPLES_ENGINE)
examples/client/%: examples/client/%.c chttp.c chttp.h
$(CC) $(CFLAGS) $< chttp.c -o $@ $(LFLAGS)
examples/server/%: examples/server/%.c chttp.c chttp.h
$(CC) $(CFLAGS) $< chttp.c -o $@ $(LFLAGS)
examples/engine/%: examples/engine/%.c chttp.c chttp.h
$(CC) $(CFLAGS) $< chttp.c -o $@ $(LFLAGS)
clean:
rm -f client_example server_example
rm -f examples/client/* examples/server/* examples/engine/*
+1 -1
View File
@@ -33,7 +33,7 @@ int main(void)
And this is an HTTP server:
```c
#include <http.h>
#include <chttp.h>
int main(void)
{
+97 -28
View File
@@ -1,9 +1,9 @@
/*
* HTTP Library - Amalgamated Source
* cHTTP Library - Amalgamated Source
* Generated automatically - do not edit manually
*/
#include "http.h"
#include "chttp.h"
#include <assert.h>
#include <errno.h>
@@ -2075,16 +2075,14 @@ void http_engine_status(HTTP_Engine *eng, int status)
eng->state = HTTP_ENGINE_STATE_SERVER_PREP_HEADER;
}
void http_engine_header(HTTP_Engine *eng, const char *src, int len)
void http_engine_header(HTTP_Engine *eng, HTTP_String str)
{
if ((eng->state & HTTP_ENGINE_STATEBIT_PREP_HEADER) == 0)
return;
if (len < 0) len = strlen(src);
// TODO: Check that the header is valid
byte_queue_write(&eng->output, src, len);
byte_queue_write(&eng->output, str.ptr, str.len);
byte_queue_write(&eng->output, "\r\n", 2);
}
@@ -2149,16 +2147,14 @@ static void complete_message_body(HTTP_Engine *eng)
byte_queue_patch(&eng->output, eng->content_length_value_offset, tmp + i, 10 - i);
}
void http_engine_body(HTTP_Engine *eng, void *src, int len)
void http_engine_body(HTTP_Engine *eng, HTTP_String str)
{
if (len < 0) len = strlen(src);
http_engine_bodycap(eng, len);
http_engine_bodycap(eng, str.len);
int cap;
char *buf = http_engine_bodybuf(eng, &cap);
if (buf) {
memcpy(buf, src, len);
http_engine_bodyack(eng, len);
memcpy(buf, str.ptr, str.len);
http_engine_bodyack(eng, str.len);
}
}
@@ -3013,15 +3009,13 @@ void socket_free(Socket *sock) {
}
}
#define COUNT(X) (sizeof(X) / sizeof((X)[0]))
int socket_wait(Socket **socks, int num_socks)
int socket_wait(Socket **socks, int num_socks) // TODO: is this used?
{
if (num_socks <= 0)
return -1;
struct pollfd polled[100]; // TODO: make this value configurable
if (num_socks > (int) COUNT(polled))
if (num_socks > (int) HTTP_COUNT(polled))
return -1;
for (;;) {
@@ -3370,7 +3364,7 @@ void http_request_line(HTTP_RequestHandle handle, HTTP_Method method, HTTP_Strin
http_engine_url(&conn->engine, method, url, 1);
}
void http_request_header(HTTP_RequestHandle handle, char *header, int len)
void http_request_header(HTTP_RequestHandle handle, HTTP_String str)
{
ClientConnection *conn = handle2clientconn(handle);
if (conn == NULL)
@@ -3378,10 +3372,10 @@ void http_request_header(HTTP_RequestHandle handle, char *header, int len)
if (conn->state != CLIENT_CONNECTION_INIT)
return;
http_engine_header(&conn->engine, header, len);
http_engine_header(&conn->engine, str);
}
void http_request_body(HTTP_RequestHandle handle, char *body, int len)
void http_request_body(HTTP_RequestHandle handle, HTTP_String str)
{
ClientConnection *conn = handle2clientconn(handle);
if (conn == NULL)
@@ -3389,7 +3383,7 @@ void http_request_body(HTTP_RequestHandle handle, char *body, int len)
if (conn->state != CLIENT_CONNECTION_INIT)
return;
http_engine_body(&conn->engine, body, len);
http_engine_body(&conn->engine, str);
}
void http_request_submit(HTTP_RequestHandle handle)
@@ -3429,6 +3423,85 @@ void http_request_free(HTTP_RequestHandle handle)
socket_free(&conn->socket);
conn->state = CLIENT_CONNECTION_FREE;
client->num_conns--;
}
static HTTP_Client *default_client___; // TODO: deinitialize the default client when http_global_free is called
static HTTP_Client *get_default_client(void)
{
if (default_client___ == NULL)
default_client___ = http_client_init();
return default_client___;
}
HTTP_Response *http_get(HTTP_String url, HTTP_String *headers, int num_headers, HTTP_RequestHandle *phandle)
{
HTTP_Client *client = get_default_client();
if (client == NULL)
return NULL;
HTTP_RequestHandle handle;
int ret = http_client_request(client, &handle);
if (ret < 0)
return NULL;
http_request_line(handle, HTTP_METHOD_GET, url);
for (int i = 0; i < num_headers; i++)
http_request_header(handle, headers[i]);
http_request_submit(handle);
ret = http_client_wait(client, NULL); // TODO: it's assumed there is only one request pending
if (ret < 0) {
http_request_free(handle); // TODO: currently free only works on completed request handles
return NULL;
}
HTTP_Response *res = http_request_result(handle);
if (res == NULL) {
http_request_free(handle);
return NULL;
}
*phandle = handle;
return res;
}
HTTP_Response *http_post(HTTP_String url, HTTP_String *headers, int num_headers, HTTP_String body, HTTP_RequestHandle *phandle)
{
HTTP_Client *client = get_default_client();
if (client == NULL)
return NULL;
HTTP_RequestHandle handle;
int ret = http_client_request(client, &handle);
if (ret < 0)
return NULL;
http_request_line(handle, HTTP_METHOD_GET, url);
for (int i = 0; i < num_headers; i++)
http_request_header(handle, headers[i]);
http_request_body(handle, body);
http_request_submit(handle);
ret = http_client_wait(client, NULL); // TODO: it's assumed there is only one request pending
if (ret < 0) {
http_request_free(handle); // TODO: currently free only works on completed request handles
return NULL;
}
HTTP_Response *res = http_request_result(handle);
if (res == NULL) {
http_request_free(handle);
return NULL;
}
*phandle = handle;
return res;
}//////////////////////////////////////////////////////////////////////
// src/server.c
//////////////////////////////////////////////////////////////////////
@@ -3559,7 +3632,6 @@ HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port,
}
}
server->num_websites = 0;
server->num_conns = 0;
server->ready_head = 0;
server->ready_count = 0;
@@ -3794,16 +3866,13 @@ void http_response_header(HTTP_ResponseHandle res, const char *fmt, ...)
va_end(args);
}
void http_response_body(HTTP_ResponseHandle res, char *src, int len)
void http_response_body(HTTP_ResponseHandle res, HTTP_String str)
{
Connection *conn = handle2conn(res);
if (conn == NULL)
return;
if (len < 0)
len = strlen(src);
http_engine_body(&conn->engine, src, len);
http_engine_body(&conn->engine, str);
}
void http_response_bodycap(HTTP_ResponseHandle res, int mincap)
@@ -4225,7 +4294,7 @@ static int serve_dynamic_route(Route *route, HTTP_Request *req, HTTP_ResponseHan
int path_len = sanitize_path(req->url.path, path_mem, (int) sizeof(path_mem));
if (path_len < 0) {
http_response_status(res, 400);
http_response_body(res, "Invalid path", -1);
http_response_body(res, HTTP_STR("Invalid path"));
http_response_done(res);
return 1;
}
@@ -4270,7 +4339,7 @@ int http_serve(char *addr, int port, HTTP_Router *router)
{
int ret;
HTTP_Server *server = http_server_init((HTTP_String) { addr, strlen(addr) }, port, 0, (HTTP_String) {}, (HTTP_String) {});
HTTP_Server *server = http_server_init_ex((HTTP_String) { addr, strlen(addr) }, port, 0, (HTTP_String) {}, (HTTP_String) {});
if (server == NULL) {
http_router_free(router);
return -1;
+19 -10
View File
@@ -1,5 +1,5 @@
/*
* HTTP Library - Amalgamated Header
* cHTTP Library - Amalgamated Header
* Generated automatically - do not edit manually
*/
@@ -61,6 +61,9 @@ HTTP_String http_trim(HTTP_String s);
// Returns the number of items of a static array.
#define HTTP_COUNT(X) (sizeof(X) / sizeof((X)[0]))
// TODO: comment
#define HTTP_UNPACK(X) (X).len, (X).ptr
// Macro used to make invariants of the code more explicit.
//
// Say you have some function that operates on two integers
@@ -288,8 +291,8 @@ HTTP_Response* http_engine_getres (HTTP_Engine *eng);
void http_engine_url (HTTP_Engine *eng, HTTP_Method method, HTTP_String url, int minor);
void http_engine_status (HTTP_Engine *eng, int status);
void http_engine_header (HTTP_Engine *eng, const char *src, int len);
void http_engine_body (HTTP_Engine *eng, void *src, int len);
void http_engine_header (HTTP_Engine *eng, HTTP_String str);
void http_engine_body (HTTP_Engine *eng, HTTP_String str);
void http_engine_bodycap (HTTP_Engine *eng, int mincap);
char* http_engine_bodybuf (HTTP_Engine *eng, int *cap);
void http_engine_bodyack (HTTP_Engine *eng, int num);
@@ -361,15 +364,11 @@ void http_request_line(HTTP_RequestHandle handle, HTTP_Method method, HTTP_Strin
// Append a header to the specified request. You must call
// this after http_request_line and may do so multiple times.
//
// TODO: use HTTP_String instead of char*+int
void http_request_header(HTTP_RequestHandle handle, char *header, int len);
void http_request_header(HTTP_RequestHandle handle, HTTP_String str);
// Append some data to the request's body. You must call
// this after either http_request_line or http_request_header.
//
// TODO: use HTTP_String instead of char*+int
void http_request_body(HTTP_RequestHandle handle, char *body, int len);
void http_request_body(HTTP_RequestHandle handle, HTTP_String str);
// Mark the initialization of the request as completed and
// perform the request.
@@ -390,6 +389,16 @@ HTTP_Response *http_request_result(HTTP_RequestHandle handle);
// TODO: allow aborting pending requests
void http_request_free(HTTP_RequestHandle handle);
// TODO: comment
HTTP_Response *http_get(HTTP_String url,
HTTP_String *headers, int num_headers,
HTTP_RequestHandle *phandle);
// TODO: comment
HTTP_Response *http_post(HTTP_String url,
HTTP_String *headers, int num_headers,
HTTP_String body, HTTP_RequestHandle *phandle);
//////////////////////////////////////////////////////////////////////
// src/server.h
//////////////////////////////////////////////////////////////////////
@@ -412,7 +421,7 @@ int http_server_wait (HTTP_Server *server, HTTP_Request **req, H
int http_server_add_website (HTTP_Server *server, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file);
void http_response_status (HTTP_ResponseHandle res, int status);
void http_response_header (HTTP_ResponseHandle res, const char *fmt, ...);
void http_response_body (HTTP_ResponseHandle res, char *src, int len);
void http_response_body (HTTP_ResponseHandle res, HTTP_String str);
void http_response_bodycap (HTTP_ResponseHandle res, int mincap);
char* http_response_bodybuf (HTTP_ResponseHandle res, int *cap);
void http_response_bodyack (HTTP_ResponseHandle res, int num);
Binary file not shown.
+2 -1
View File
@@ -1,3 +1,4 @@
#include <stdio.h>
#include <chttp.h>
// This is an example of how to use cHTTP to perform
@@ -46,7 +47,7 @@ int main(void)
);
}
printf("body: %.*s\n", res->body.len, res->body.ptr);
printf("body: %.*s\n", HTTP_UNPACK(res->body));
// When we are done reading from the response object
// we must free the request's resources.
Binary file not shown.
+1 -2
View File
@@ -1,8 +1,7 @@
#include <http.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../http.h"
#include <chttp.h>
int main(int argc, char **argv) {
if (argc < 2) {
Binary file not shown.
+3 -5
View File
@@ -2,9 +2,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <http.h>
#define COUNT(X) (sizeof(X) / sizeof((X)[0]))
#include <chttp.h>
#define BLK "\e[0;30m"
#define RED "\e[0;31m"
@@ -149,7 +147,7 @@ int main(int argc, char **argv)
return -1;
}
http_request_line(req, HTTP_METHOD_GET, start_url);
http_request_header(req, "User-Agent: Simple crawler", -1);
http_request_header(req, HTTP_STR("User-Agent: Simple crawler"));
http_request_submit(req);
for (;;) {
@@ -188,7 +186,7 @@ int main(int argc, char **argv)
continue;
http_request_line(req, HTTP_METHOD_GET, url);
http_request_header(req, "User-Agent: Simple crawler", -1);
http_request_header(req, HTTP_STR("User-Agent: Simple crawler"));
http_request_submit(req);
}
}
+1 -1
View File
@@ -18,7 +18,7 @@
#define CLOSE_SOCKET close
#endif
#include <http.h>
#include <chttp.h>
// This example showcases how to use the engine interface
// to build a blocking HTTP server that works on Windows
+1 -1
View File
@@ -1,7 +1,7 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include <http.h>
#include <chttp.h>
#define MAX_CLIENTS (1<<10)
Binary file not shown.
+3 -2
View File
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdbool.h>
#include <http.h>
#include <chttp.h>
// This example shows how to set up a basic HTTP server
@@ -30,7 +31,7 @@ int main(void)
HTTP_ResponseHandle res;
// Block until a request is available
int ret = http_server_wait(server, &res, &res);
int ret = http_server_wait(server, &req, &res);
// The wait functions returns 0 on success and -1
// on error. By "error" I mean an unrecoverable
Binary file not shown.
+3 -2
View File
@@ -1,4 +1,5 @@
#include <http.h>
#include <string.h>
#include <chttp.h>
// This example shows how to generate response bodies
// using the zero-copy API.
@@ -18,7 +19,7 @@ int main(void)
HTTP_Request *req;
HTTP_ResponseHandle res;
int ret = http_server_wait(server, &res, &res);
int ret = http_server_wait(server, &req, &res);
if (ret < 0) return -1;
http_response_status(res, 200);
Binary file not shown.
+3 -2
View File
@@ -1,4 +1,5 @@
#include <http.h>
#include <stddef.h>
#include <chttp.h>
// This example shows how undo a response that is being built
// when an error occurs.
@@ -14,7 +15,7 @@ int main(void)
HTTP_Request *req;
HTTP_ResponseHandle res;
int ret = http_server_wait(server, &res, &res);
int ret = http_server_wait(server, &req, &res);
if (ret < 0) return -1;
// Say we are building a request..
+1 -1
View File
@@ -1,5 +1,5 @@
#include <stdbool.h>
#include <http.h>
#include <chttp.h>
// NOTE: This example doesn't work yet!
+1 -1
View File
@@ -1,5 +1,5 @@
#include <stdbool.h>
#include <http.h>
#include <chttp.h>
// This example shows how to set up an HTTPS (HTTP over TLS)
// server.
@@ -1,4 +1,4 @@
#include <http.h>
#include <chttp.h>
// This is an example of how to serve different websites
// over a single HTTPS server instance.
@@ -29,7 +29,7 @@ int main(void)
// First, set up an HTTPS server instance with one
// of the certificate. This will act as default certificate
// when ecrypted connections don't target a specific domain.
HTTP_Server *server = http_server_init(
HTTP_Server *server = http_server_init_ex(
HTTP_STR("127.0.0.1"), 8080, 8443,
HTTP_STR("websiteA_cert.pem"),
HTTP_STR("websiteA_key.pem")
+3 -3
View File
@@ -198,7 +198,7 @@ def main():
print("Writing chttp.h...")
with open("chttp.h", 'w', encoding='utf-8') as f:
f.write('/*\n')
f.write(' * HTTP Library - Amalgamated Header\n')
f.write(' * cHTTP Library - Amalgamated Header\n')
f.write(' * Generated automatically - do not edit manually\n')
f.write(' */\n\n')
f.write('#ifndef HTTP_AMALGAMATION_H\n')
@@ -215,10 +215,10 @@ def main():
print("Writing chttp.c...")
with open("chttp.c", 'w', encoding='utf-8') as f:
f.write('/*\n')
f.write(' * HTTP Library - Amalgamated Source\n')
f.write(' * cHTTP Library - Amalgamated Source\n')
f.write(' * Generated automatically - do not edit manually\n')
f.write(' */\n\n')
f.write('#include "http.h"\n\n')
f.write('#include "chttp.h"\n\n')
f.write(source)
print("Amalgamation complete!")
+4 -4
View File
@@ -311,7 +311,7 @@ void http_request_line(HTTP_RequestHandle handle, HTTP_Method method, HTTP_Strin
http_engine_url(&conn->engine, method, url, 1);
}
void http_request_header(HTTP_RequestHandle handle, char *header, int len)
void http_request_header(HTTP_RequestHandle handle, HTTP_String str)
{
ClientConnection *conn = handle2clientconn(handle);
if (conn == NULL)
@@ -319,10 +319,10 @@ void http_request_header(HTTP_RequestHandle handle, char *header, int len)
if (conn->state != CLIENT_CONNECTION_INIT)
return;
http_engine_header(&conn->engine, header, len);
http_engine_header(&conn->engine, str);
}
void http_request_body(HTTP_RequestHandle handle, char *body, int len)
void http_request_body(HTTP_RequestHandle handle, HTTP_String str)
{
ClientConnection *conn = handle2clientconn(handle);
if (conn == NULL)
@@ -330,7 +330,7 @@ void http_request_body(HTTP_RequestHandle handle, char *body, int len)
if (conn->state != CLIENT_CONNECTION_INIT)
return;
http_engine_body(&conn->engine, body, len);
http_engine_body(&conn->engine, str);
}
void http_request_submit(HTTP_RequestHandle handle)
+2 -6
View File
@@ -65,15 +65,11 @@ void http_request_line(HTTP_RequestHandle handle, HTTP_Method method, HTTP_Strin
// Append a header to the specified request. You must call
// this after http_request_line and may do so multiple times.
//
// TODO: use HTTP_String instead of char*+int
void http_request_header(HTTP_RequestHandle handle, char *header, int len);
void http_request_header(HTTP_RequestHandle handle, HTTP_String str);
// Append some data to the request's body. You must call
// this after either http_request_line or http_request_header.
//
// TODO: use HTTP_String instead of char*+int
void http_request_body(HTTP_RequestHandle handle, char *body, int len);
void http_request_body(HTTP_RequestHandle handle, HTTP_String str);
// Mark the initialization of the request as completed and
// perform the request.
+6 -10
View File
@@ -774,16 +774,14 @@ void http_engine_status(HTTP_Engine *eng, int status)
eng->state = HTTP_ENGINE_STATE_SERVER_PREP_HEADER;
}
void http_engine_header(HTTP_Engine *eng, const char *src, int len)
void http_engine_header(HTTP_Engine *eng, HTTP_String str)
{
if ((eng->state & HTTP_ENGINE_STATEBIT_PREP_HEADER) == 0)
return;
if (len < 0) len = strlen(src);
// TODO: Check that the header is valid
byte_queue_write(&eng->output, src, len);
byte_queue_write(&eng->output, str.ptr, str.len);
byte_queue_write(&eng->output, "\r\n", 2);
}
@@ -848,16 +846,14 @@ static void complete_message_body(HTTP_Engine *eng)
byte_queue_patch(&eng->output, eng->content_length_value_offset, tmp + i, 10 - i);
}
void http_engine_body(HTTP_Engine *eng, void *src, int len)
void http_engine_body(HTTP_Engine *eng, HTTP_String str)
{
if (len < 0) len = strlen(src);
http_engine_bodycap(eng, len);
http_engine_bodycap(eng, str.len);
int cap;
char *buf = http_engine_bodybuf(eng, &cap);
if (buf) {
memcpy(buf, src, len);
http_engine_bodyack(eng, len);
memcpy(buf, str.ptr, str.len);
http_engine_bodyack(eng, str.len);
}
}
+2 -2
View File
@@ -108,8 +108,8 @@ HTTP_Response* http_engine_getres (HTTP_Engine *eng);
void http_engine_url (HTTP_Engine *eng, HTTP_Method method, HTTP_String url, int minor);
void http_engine_status (HTTP_Engine *eng, int status);
void http_engine_header (HTTP_Engine *eng, const char *src, int len);
void http_engine_body (HTTP_Engine *eng, void *src, int len);
void http_engine_header (HTTP_Engine *eng, HTTP_String str);
void http_engine_body (HTTP_Engine *eng, HTTP_String str);
void http_engine_bodycap (HTTP_Engine *eng, int mincap);
char* http_engine_bodybuf (HTTP_Engine *eng, int *cap);
void http_engine_bodyack (HTTP_Engine *eng, int num);
+2 -2
View File
@@ -358,7 +358,7 @@ static int serve_dynamic_route(Route *route, HTTP_Request *req, HTTP_ResponseHan
int path_len = sanitize_path(req->url.path, path_mem, (int) sizeof(path_mem));
if (path_len < 0) {
http_response_status(res, 400);
http_response_body(res, "Invalid path", -1);
http_response_body(res, HTTP_STR("Invalid path"));
http_response_done(res);
return 1;
}
@@ -403,7 +403,7 @@ int http_serve(char *addr, int port, HTTP_Router *router)
{
int ret;
HTTP_Server *server = http_server_init((HTTP_String) { addr, strlen(addr) }, port, 0, (HTTP_String) {}, (HTTP_String) {});
HTTP_Server *server = http_server_init_ex((HTTP_String) { addr, strlen(addr) }, port, 0, (HTTP_String) {}, (HTTP_String) {});
if (server == NULL) {
http_router_free(router);
return -1;
+2 -6
View File
@@ -133,7 +133,6 @@ HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port,
}
}
server->num_websites = 0;
server->num_conns = 0;
server->ready_head = 0;
server->ready_count = 0;
@@ -368,16 +367,13 @@ void http_response_header(HTTP_ResponseHandle res, const char *fmt, ...)
va_end(args);
}
void http_response_body(HTTP_ResponseHandle res, char *src, int len)
void http_response_body(HTTP_ResponseHandle res, HTTP_String str)
{
Connection *conn = handle2conn(res);
if (conn == NULL)
return;
if (len < 0)
len = strlen(src);
http_engine_body(&conn->engine, src, len);
http_engine_body(&conn->engine, str);
}
void http_response_bodycap(HTTP_ResponseHandle res, int mincap)
+1 -1
View File
@@ -22,7 +22,7 @@ int http_server_wait (HTTP_Server *server, HTTP_Request **req, H
int http_server_add_website (HTTP_Server *server, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file);
void http_response_status (HTTP_ResponseHandle res, int status);
void http_response_header (HTTP_ResponseHandle res, const char *fmt, ...);
void http_response_body (HTTP_ResponseHandle res, char *src, int len);
void http_response_body (HTTP_ResponseHandle res, HTTP_String str);
void http_response_bodycap (HTTP_ResponseHandle res, int mincap);
char* http_response_bodybuf (HTTP_ResponseHandle res, int *cap);
void http_response_bodyack (HTTP_ResponseHandle res, int num);