Windows errata or my fault?
- From: Rick Jones <rick jones2 hp com>
- To: gtk-list gnome org
- Subject: Windows errata or my fault?
- Date: Mon, 13 Mar 2006 10:25:46 -0800
I've been tyring various little programs to get a feel for glib on
windows. One of them is attached. The idea is to connect to the echo
port on a system, send it hello world from time to time, and get those
bytes back.
I have one of those "it works on linux but not here" situations. Under
linux (debian 3.1 I think, recent glib from testing) the output looks
something like:
raj tardy:~$ ./gplay
Starting loop...
writing 'Hello World' to the channel
Read:
Hello World
from the source
Callback called 1th time with 0x804c730
Read:
Hello World
from the source
Callback called 2th time with 0x804c730
Read:
Hello World
from the source
Callback called 3th time with 0x804c730
Read:
Hello World
from the source
Callback called 4th time with 0x804c730
Read:
Hello World
from the source
Callback called 5th time with 0x804c730
Read:
Hello World
from the source
Callback called 6th time with 0x804c730
Time to quit
Under Windows XP with glib 2.10 it stops after this:
Starting loop...
writing 'Hello World' to the channel
Read:
Hello World
from the source
Callback called 1th time with 00354620
Read:
Hello World
from the source
so the first hello world went-out to the remote, we got the reply, the
timer event happened the first time and wrote hello world again, and it
seems we got it back from the remote, but the next timer event didn't
seem to happen.
rick jones
#include <glib.h>
#include <sys/types.h>
#ifndef G_OS_WIN32
#include <netdb.h>
#include <sys/socket.h>
#define INVALID_SOCKET -1
#define SOCKET int
#define __cdecl
#else
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define close(x) closesocket(x)
#endif
/*
establish_control()
set-up the control connection between netperf and the netserver so we
can actually run some tests. if we cannot establish the control
connection, that may or may not be a good thing, so we will let the
caller decide what to do.
to assist with pesky end-to-end-unfriendly things like firewalls, we
allow the caller to specify both the remote hostname and port, and the
local addressing info. i believe that in theory it is possible to
have an IPv4 endpoint and an IPv6 endpoint communicate with one
another, but for the time being, we are only going to take-in one
requested address family parameter. this means that the only way
(iirc) that we might get a mixed-mode connection would be if the
address family is specified as AF_UNSPEC, and getaddrinfo() returns
different families for the local and server names.
the "names" can also be IP addresses in ASCII string form.
raj 2003-02-27 */
static SOCKET
establish_control_internal(char *hostname,
char *port,
int remfam,
char *localhost,
char *localport,
int locfam)
{
int not_connected;
SOCKET control_sock;
int count;
int error;
struct addrinfo hints;
struct addrinfo *local_res;
struct addrinfo *remote_res;
struct addrinfo *local_res_temp;
struct addrinfo *remote_res_temp;
/* first, we do the remote */
memset(&hints, 0, sizeof(hints));
hints.ai_family = remfam;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = 0|AI_CANONNAME;
count = 0;
do {
error = getaddrinfo((char *)hostname,
(char *)port,
&hints,
&remote_res);
count += 1;
if (error == EAI_AGAIN) {
g_usleep(1000000);
}
} while ((error == EAI_AGAIN) && (count <= 5));
if (error) {
return(INVALID_SOCKET);
}
/* now we do the local */
memset(&hints, 0, sizeof(hints));
hints.ai_family = locfam;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE|AI_CANONNAME;
count = 0;
do {
count += 1;
error = getaddrinfo((char *)localhost,
(char *)localport,
&hints,
&local_res);
if (error == EAI_AGAIN) {
g_usleep(1000000);
}
} while ((error == EAI_AGAIN) && (count <= 5));
if (error) {
return(INVALID_SOCKET);
}
not_connected = 1;
local_res_temp = local_res;
remote_res_temp = remote_res;
/* we want to loop through all the possibilities. looping on the
local addresses will be handled within the while loop. I suppose
these is some more "C-expert" way to code this, but it has not
lept to mind just yet :) raj 2003-02024 */
while (remote_res_temp != NULL) {
/* I am guessing that we should use the address family of the
local endpoint, and we will not worry about mixed family types
- presumeably the stack or other transition mechanisms will be
able to deal with that for us. famous last words :) raj 2003-02-26 */
control_sock = socket(local_res_temp->ai_family,
SOCK_STREAM,
0);
if (control_sock == INVALID_SOCKET) {
/* at some point we'll need a more generic "display error"
message for when/if we use GUIs and the like. unlike a bind
or connect failure, failure to allocate a socket is
"immediately fatal" and so we return to the caller. raj 2003-02-24 */
return(INVALID_SOCKET);
}
/* if we are going to control the local enpoint addressing, we
need to call bind. of course, we should probably be setting one
of the SO_REUSEmumble socket options? raj 2005-02-04 */
if (bind(control_sock,
local_res_temp->ai_addr,
local_res_temp->ai_addrlen) == 0) {
if (connect(control_sock,
remote_res_temp->ai_addr,
remote_res_temp->ai_addrlen) == 0) {
/* we have successfully connected to the remote netserver */
not_connected = 0;
/* this should get us out of the while loop */
break;
} else {
/* the connect call failed */
}
}
else {
/* the bind failed */
}
if ((local_res_temp = local_res_temp->ai_next) == NULL) {
/* wrap the local and move to the next server, don't forget to
close the current control socket. raj 2003-02-24 */
local_res_temp = local_res;
/* the outer while conditions will deal with the case when we
get to the end of all the possible remote addresses. */
remote_res_temp = remote_res_temp->ai_next;
/* it is simplest here to just close the control sock. since
this is not a performance critical section of code, we
don't worry about overheads for socket allocation or
close. raj 2003-02-24 */
}
close(control_sock);
}
/* we no longer need the addrinfo stuff */
freeaddrinfo(local_res);
freeaddrinfo(remote_res);
/* so, we are either connected or not */
if (not_connected) {
return(INVALID_SOCKET);
}
/* at this point, we are connected. we probably want some sort of
version check with the remote at some point. raj 2003-02-24 */
return(control_sock);
}
GIOChannel *my_channel;
gchar *hello="Hello World\n";
gboolean read_something(GIOChannel *source,
GIOCondition condition,
gpointer data)
{
gchar buf[1024];
GIOStatus status;
gsize bytes_read;
GError *error=NULL;
while ((status =
g_io_channel_read_chars(source,buf,1023,&bytes_read,&error)) ==
G_IO_STATUS_NORMAL) {
buf[bytes_read] = '\0';
g_print("Read:\n %s from the source\n",buf);
}
if (error) {
g_warning("g_io_channel_read_chars %s %d %s\n",
g_quark_to_string(error->domain),
error->code,
error->message);
g_clear_error(&error);
}
return(TRUE);
}
static void callback(gpointer data)
{
gsize bytes_written;
GError *error=NULL;
GIOStatus status;
static int count=0;
g_print("Callback called %dth time with %p\n",++count,data);
status = g_io_channel_write_chars(my_channel,
hello,
strlen(hello),
&bytes_written,
&error);
g_print("after write in call back status is %d\n",status);
if (error) {
g_warning("g_io_write_channel_chars %s %d %s\n",
g_quark_to_string(error->domain),
error->code,
error->message);
g_clear_error(&error);
}
if (count > 5) {
g_print("Time to quit\n");
g_main_loop_quit(data);
}
}
int __cdecl main(int argc, char *argv[])
{
SOCKET control;
guint watch_id;
GIOStatus status;
GError *error = NULL;
gsize bytes_written;
GMainLoop *loop;
#ifdef G_OS_WIN32
WSADATA wsa_data ;
/* Initialize the winsock lib ( version 2.2 ) */
if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){
g_print("WSAStartup() failed : %d\n", GetLastError()) ;
return 1 ;
}
#endif
control = establish_control_internal("tardy.cup.hp.com",
"echo",
AF_UNSPEC,
"0.0.0.0",
"0",
AF_UNSPEC);
loop = g_main_loop_new(NULL, FALSE);
g_print("Starting loop...\n");
#ifndef G_OS_WIN32
my_channel = g_io_channel_unix_new(control);
#else
my_channel = g_io_channel_win32_new_socket(control);
#endif
status = g_io_channel_set_flags(my_channel,G_IO_FLAG_NONBLOCK,&error);
if (error) {
g_warning("g_io_channel_set_flags %s %d %s\n",
g_quark_to_string(error->domain),
error->code,
error->message);
g_clear_error(&error);
}
status = g_io_channel_set_encoding(my_channel,NULL,&error);
if (error) {
g_warning("g_io_channel_set_encoding %s %d %s\n",
g_quark_to_string(error->domain),
error->code,
error->message);
g_clear_error(&error);
}
g_io_channel_set_buffered(my_channel,FALSE);
/* loop is passed just to have something passed */
watch_id = g_io_add_watch(my_channel, G_IO_IN, read_something, loop);
status = g_io_channel_write_chars(my_channel,
hello,
strlen(hello),
&bytes_written,
&error);
if (error) {
g_warning("g_io_write_channel_chars %s %d %s\n",
g_quark_to_string(error->domain),
error->code,
error->message);
g_clear_error(&error);
}
g_print("writing 'Hello World' to the channel\n");
g_timeout_add(1000, (GSourceFunc)callback, loop);
g_main_loop_run(loop);
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]