Hi,
I have written some very simple test server using apr (src included).
I met a problem on Windoze NT (among other things):
When the receive timeout occures on a call apr_socket_recv() in the
serving thread, a call to apr_socket_accept() is also interrupted in the
main thread. Next accept on the same socket ends on "socket operation on
non-socket".
The code output on Windoze NT4.0 (service pack 6) follows.
I simply ran the threadsock.exe and created one connection using the
netcat (from other host) and waited for timeout.
apr_app_initialize(): done
apr_pool_create(): done
apr_socket_create(): done
apr_sockaddr_info_get(): done
apr_socket_bind(): done
apr_socket_listen(): done
apr_socket_accept(): done
apr_thread_create(): done
apr_socket_accept(): apr_thread_detach(): done
apr_socket_timeout_set(): done
apr_socket_send(): done
- sent 13 bytes
socket recv: apr_socket_recv() failed: Connection timed out
failed: Interrupted system call
apr_socket_accept(): failed: Socket operation on non-socket
String "failed: Interrupted system call" belongs to preceding
"apr_socket_accept():" of course. :-)
The listening master socket is probably away. This is apr or windoze
related behavior? (On Linux i386 this works like I expected.)
Is it possible to write simple server like this (performance doesn't
matter) without need a special code for Win32?
Excuse my English, please.
Thanks
--
Zito
#include <stdio.h>
#include <stdlib.h>
#include <apr.h>
#include <apr_general.h>
#include <apr_network_io.h>
#include <apr_pools.h>
#include <apr_thread_proc.h>
#include <apr_time.h>
#define ASSERT_APR_SUCCESS(heading, op) \
{ \
apr_status_t rv; \
fprintf(stderr, heading ": "); \
if ( (rv = op) != APR_SUCCESS ) \
{ \
char buf[128]; \
fprintf(stderr, "failed: %s\n", \
apr_strerror(rv, buf, sizeof(buf))); \
exit(1); \
} \
fprintf(stderr, "done\n"); \
}
static void * APR_THREAD_FUNC thread_serv_start(apr_thread_t *thd, void *data);
int main(int argc, char const * const argv[])
{
apr_status_t rv;
apr_pool_t *pglobal;
apr_socket_t *sd, *sd2;
apr_sockaddr_t *sa;
apr_thread_t *child;
ASSERT_APR_SUCCESS("apr_app_initialize()",
apr_app_initialize(&argc, &argv, NULL));
atexit(&apr_terminate);
ASSERT_APR_SUCCESS("apr_pool_create()",
apr_pool_create(&pglobal, NULL));
ASSERT_APR_SUCCESS("apr_socket_create()",
apr_socket_create(&sd, APR_INET, SOCK_STREAM, pglobal));
ASSERT_APR_SUCCESS("apr_sockaddr_info_get()",
apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_INET, 12345,
0, pglobal));
ASSERT_APR_SUCCESS("apr_socket_bind()",
apr_socket_bind(sd, sa));
ASSERT_APR_SUCCESS("apr_socket_listen()",
apr_socket_listen(sd, 1));
while ( 1 )
{
fprintf(stderr, "apr_socket_accept(): ");
if ( (rv = apr_socket_accept(&sd2, sd, pglobal)) != APR_SUCCESS )
{
char buf[128];
fprintf(stderr, "failed: %s\n",
apr_strerror(rv, buf, sizeof(buf)));
if ( APR_STATUS_IS_EINTR(rv) )
continue;
exit(1);
}
fprintf(stderr, "done\n");
ASSERT_APR_SUCCESS("apr_thread_create()",
apr_thread_create(&child, NULL,
thread_serv_start, sd2, pglobal));
}
ASSERT_APR_SUCCESS("apr_socket_close()",
apr_socket_close(sd));
fprintf(stderr, "apr_pool_destroy(): ");
apr_pool_destroy(pglobal);
fprintf(stderr, "done\n");
return 0;
}
static void * APR_THREAD_FUNC thread_serv_start(apr_thread_t *thd, void *data)
{
apr_socket_t *sd2 = (apr_socket_t *)data;
apr_status_t rv;
apr_size_t n;
char buf[256];
apr_sleep(10000); /* glibc bug workaround */
ASSERT_APR_SUCCESS("apr_thread_detach()",
apr_thread_detach(thd));
ASSERT_APR_SUCCESS("apr_socket_timeout_set()",
apr_socket_timeout_set(sd2, 10000000L));
#define HELLO_STR "Hello world!\n"
n = strlen(HELLO_STR);
ASSERT_APR_SUCCESS("apr_socket_send()",
apr_socket_send(sd2, HELLO_STR, &n));
fprintf(stderr, " - sent %d bytes\n", n);
// ASSERT_APR_SUCCESS("apr_socket_shutdown()",
// apr_socket_shutdown(sd2, APR_SHUTDOWN_WRITE));
fprintf(stderr, "socket recv: ");
n = sizeof(buf);
if ( (rv = apr_socket_recv(sd2, buf, &n)) != APR_SUCCESS
&& rv != APR_EOF )
{
fprintf(stderr, "apr_socket_recv() failed: %s\n",
apr_strerror(rv, buf, sizeof(buf)));
if ( ! APR_STATUS_IS_TIMEUP(rv) )
exit(1);
}
else
{
fprintf(stderr, "done\n");
fprintf(stderr, " - read %d bytes\n", n);
fwrite(buf, n, 1, stderr);
}
ASSERT_APR_SUCCESS("apr_socket_close()",
apr_socket_close(sd2));
apr_thread_exit(thd, APR_SUCCESS);
return NULL;
}