RE: poll with timeout 0 in main loop
- From: Juan Pablo L. <jpablolorenzetti hotmail com>
- To: <chris cvine freeserve co uk>
- Cc: gtk-app-devel-list gnome org
- Subject: RE: poll with timeout 0 in main loop
- Date: Fri, 22 Oct 2010 10:37:01 +0000
i attached the code but did not make thru, here is the server code:
GMTCPServer *tcp_server_new(const Configurations *p_configurations)
{
GMTCPServer *new_server;
GError *error = NULL;
int fd;
// create a new tcp server object
new_server = g_new(GMTCPServer,1);
// get the configurations reference
new_server->configurations = p_configurations;
// create the context for this thread
new_server->context = g_main_context_new();
// initialize the list of clients
new_server->clients_list = g_ptr_array_new_with_free_func((void*)gm_connection_destroy);
// create the server socket
fd = tcp_server_listerner_new(new_server->configurations,&error);
if(fd < 0)
{
g_error("Could not create listener, server creation aborted: %s",error->message);
g_error_free(error);
return NULL;
}
// create the GIOChannel for the server socket
new_server->socket = g_io_channel_unix_new(fd);
// set the encoding safe to read binary data on the server GIOChannel
g_io_channel_set_encoding(new_server->socket,NULL,NULL);
// create a source for connection events on the server socket
new_server->event_source =
g_io_create_watch(new_server->socket,G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL);
// set the callback function to handle connection events
g_source_set_callback(new_server->event_source,(GSourceFunc)tcp_server_handle_connection_events,new_server,NULL);
// attach the server socket connection event source to the server context
g_source_attach(new_server->event_source,new_server->context);
// create the callback event source
new_server->callback_source = async_callback_new();
// attach the callback event source to the context
g_source_attach(new_server->callback_source,new_server->context);
// create the main loop for this thread
new_server->main_loop = g_main_loop_new(new_server->context,FALSE);
// the thread will be started later
new_server->server_thread = NULL;
return new_server;
}
void tcp_server_destroy(GMTCPServer *p_server)
{
g_message("Destroying GoMobile server ...");
// quit the main loop
g_main_loop_quit(p_server->main_loop);
// join the server thread
if(p_server->server_thread != NULL)
{
g_thread_join(p_server->server_thread);
}
// remove the server socket connection event source from the context
g_source_destroy(p_server->event_source);
// remove callback event source from the server context
g_source_destroy(p_server->callback_source);
// close and free server socket resources
g_io_channel_shutdown(p_server->socket,TRUE,NULL);
// close all client connections
g_ptr_array_free(p_server->clients_list,TRUE);
// free resources associated with event source
g_source_unref(p_server->event_source);
// free resources associated with the callback event source
g_source_unref(p_server->callback_source);
// free the resources in the server socket
g_io_channel_unref(p_server->socket);
// destroy the main loop
g_main_loop_unref(p_server->main_loop);
// free the context resources
g_main_context_unref(p_server->context);
// delete the memory allocated by the tcp object itself
g_free(p_server);
g_message("Done");
}
void tcp_server_run(GMTCPServer *p_server)
{
// run the main loop now
g_main_loop_run(p_server->main_loop);
g_thread_exit(NULL);
}
int tcp_server_listerner_new(const Configurations *p_configurations,GError **p_error)
{
int fd;
struct sockaddr_in servAddr;
int set_option = 1;
// create the socket
fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(fd < 0)
{
*p_error = g_error_new(G_IO_CHANNEL_ERROR,G_IO_CHANNEL_ERROR_FAILED,"Could not create server socket:
%s",strerror(errno));
return -1;
}
// set some options on the socket
fcntl(fd,F_SETFL,O_NONBLOCK);// set the socket non-blocking
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&set_option,sizeof(set_option));// reuse address
setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,&set_option,sizeof(set_option));// send keep alive messages
// construct local address structure
memset(&servAddr,0x00, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(p_configurations->tcp_server.interface);
servAddr.sin_port = htons(p_configurations->tcp_server.port);
// Bind to the local address
if(bind(fd,(struct sockaddr*)&servAddr,sizeof(servAddr)) < 0)
{
*p_error = g_error_new(G_IO_CHANNEL_ERROR,G_IO_CHANNEL_ERROR_FAILED,"Could not bind server socket:
%s",strerror(errno));
// close the socket
close(fd);
return -1;
}
if(listen(fd,10) < 0)
{
*p_error = g_error_new(G_IO_CHANNEL_ERROR,G_IO_CHANNEL_ERROR_FAILED,"Could not start listening on the
server socket: %s",strerror(errno));
// close the socket
close(fd);
return -1;
}
return fd;
}
gboolean tcp_server_handle_connection_events(GIOChannel *p_source,GIOCondition p_condition,GMTCPServer
*p_server)
{
TCPClientConnection *client = NULL;
struct sockaddr_in sockaddr;
socklen_t client_fd_len;
int client_fd;
// GError *error = NULL;
int set_option = 1;
if(p_condition & (G_IO_IN|G_IO_PRI))
{
// accept the connection now
client_fd_len = sizeof(sockaddr);
if((client_fd = accept(g_io_channel_unix_get_fd(p_server->socket),(struct
sockaddr*)&sockaddr,&client_fd_len)) < 0)
{
g_error("Could not accept new connection: %s",strerror(errno));
return TRUE;
}
fcntl(client_fd,F_SETFL,O_NONBLOCK);// set the socket non-blocking
setsockopt(client_fd,SOL_SOCKET,SO_KEEPALIVE,&set_option,sizeof(set_option));// send keep alive
messages
g_message("New connection attempt");
// create a client connection
client = gm_connection_new(client_fd,p_server);
// get the address for this client
if (inet_ntop(AF_INET,&sockaddr.sin_addr.s_addr,client->ip,sizeof(client->ip)) != NULL)
{
client->port = ntohs(sockaddr.sin_port);
g_message("Successfully accepted new client connection from %s:%d",client->ip,client->port);
}
else
{
client->ip[0] = 0;
client->port = -1;
g_message("Successfully accepted new client connection from an unknown location");
}
// run the connection thread
client->connection_thread =
g_thread_create((GThreadFunc)gm_connection_run,client,TRUE,/*&error*/NULL);
if(client->connection_thread == NULL)
{
g_error("Could not start new connection for client: %s:%d, will end this
connection",client->ip,client->port);
gm_connection_destroy(client);
}
else
{
// push it into the client array
g_ptr_array_add(p_server->clients_list,client);
g_message("Successfully started new connection");
}
return TRUE;
}
// an error happened
// show an error message and try to get a description from errno
g_warning("An error occurred on the server socket: %s",strerror(errno));
return TRUE;
}
gboolean tcp_server_remove_connection(TCPClientConnection *p_client)
{
// remove a client
g_ptr_array_remove(p_client->my_server->clients_list,p_client);
return TRUE;
}
and the server is astarted only once from the main thread.
regarding GIO, i like to have like control of things so i m just sticking with glib, what i need from glib
are the special structucures like
array pointers, sometimes the strings as containers and of course, the mail loop :) ....
Date: Fri, 22 Oct 2010 10:17:30 +0100
From: chris cvine freeserve co uk
To: jpablolorenzetti hotmail com
CC: maginot junior gmail com; gtk-app-devel-list gnome org
Subject: Re: poll with timeout 0 in main loop
On Fri, 22 Oct 2010 02:57:59 +0000
Juan Pablo L. <jpablolorenzetti hotmail com> wrote:
hi, this is the code that makes the server socket
[snip]
There doesn't seem anything especially wrong with this but you have a
lot of code missing. In particular, what does your
tcp_server_handle_connection_events() callback do, such as when it
encounters errors (you specify that the callback is to be entered in a
case of G_IO_NVAL and G_IO_ERR), and how do you disconnect sources from
the main loop when they are finished with (I notice also you don't
unref the sources after attaching them to the main loop). Quite
possibly you are looping in a case of errors or defunct sources.
Probably the best thing you can do is come up with the smallest test
case which demonstrates the error (with say just one socket worker
thread) and post it here.
This is off topic, but glib's gio makes it trivial to construct new
server threads and it does all the hard stuff for you, but you need
glib version 2.22 for gio's socket API. Glib's gio has no relationship
with GIOChannels, despite the similar names.
Chris
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]