From: Vincent T. <vt...@un...> - 2007-06-15 17:58:39
|
Hey, I am porting a linux library to windows. That library implements an event loop, ala glib. Something like: while (1) { main_loop_iterate (); } with: main_loop_iterate () { if (event) { /* do something */ } select (fd,***); } so, a loop using select(). I call that loop 'l1' If another loop, called 'l2', runs (in another thread), i have to make l1 being aware of all the events that l2 can send (as they live in different threads). On linux, I create with pipe() 2 file descriptors (fd) named fd1 and fd2. fd1 is associated to l1 and fd2 is associated to l2. If an event is sent by l2, I write in fd2 the data. The pipe send the data to fd1 and with select(), l1 can retrieve those data. For that, I "associate" to fd1 a callback and the data with a function, named fd_handler_add, which takes as parameters a fd, a callback and the data to pass. Hence the code is: pipe (&fd1, &fd2); /* it's not the correct syntax, it's just to fix ideas */ fd_handler_add (fd1, my_callback, my_data); /* now, l1 knows that my_callback and my_data are associated to fd1 */ /* l2, in another thread */ while (1) { if (event) write (fd2, my_data); } /* l1 */ while (1) { if (select (fd1) >= 0) { /* cb is my callback, d is my data, got with fd_handler_add */ cb (d); } } So, when I write in fd2, my_callback (my_data) is called in l1. Now, my problem comes from l2, which is the message loop of a Windows window. So I have to send the data of l2 (Windows loop) to l1 (linux loop, using select()). I've seen that select() is available in winsock2.h, but for sockets (_pipe exists, in CRT, but it's for fd's). My question is the following: Is it possible to create 2 sockets (named fd1 and fd2, to fix ideas), the former for l1, the latter for l2, to link them (like pipe() does), to read and write in those sockets so that select can get the data on fd1, sent from fd2 ? In that case, my modifications would be minor. If not, does someone see another solution ? thank you very much Vincent Torri |
From: Brian D. <br...@de...> - 2007-06-15 18:50:01
|
Vincent Torri wrote: > Is it possible to create 2 sockets (named fd1 and fd2, to fix ideas), the > former for l1, the latter for l2, to link them (like pipe() does), to read > and write in those sockets so that select can get the data on fd1, sent > from fd2 ? In that case, my modifications would be minor. You could do that, but you'd have to explicitly connect them (socket(), bind(), listen(), accept(), etc.), just as if you were writing standard TCP/IP client-server networking code. > If not, does someone see another solution ? WaitForMultipleObjects() is the Win32 API analogue to unix select. However remember that it's working on the Win32 level so it takes handles not fds. You can use the _getosfhandle() function to get the underlying handle of a fd. MSDN section on various synchronization APIs: <http://msdn2.microsoft.com/en-us/library/ms686967.aspx>. Brian |
From: Vincent T. <vt...@un...> - 2007-06-15 19:06:07
|
On Fri, 15 Jun 2007, Brian Dessent wrote: > Vincent Torri wrote: > >> Is it possible to create 2 sockets (named fd1 and fd2, to fix ideas), the >> former for l1, the latter for l2, to link them (like pipe() does), to read >> and write in those sockets so that select can get the data on fd1, sent >> from fd2 ? In that case, my modifications would be minor. > > You could do that, but you'd have to explicitly connect them (socket(), > bind(), listen(), accept(), etc.), just as if you were writing standard > TCP/IP client-server networking code. too complicated for me :) >> If not, does someone see another solution ? > > WaitForMultipleObjects() is the Win32 API analogue to unix select. > However remember that it's working on the Win32 level so it takes > handles not fds. You can use the _getosfhandle() function to get the > underlying handle of a fd. and the fd's are created with _pipe() (http://msdn2.microsoft.com/en-us/library/edze9h7e(VS.80).aspx) ? > > MSDN section on various synchronization APIs: > <http://msdn2.microsoft.com/en-us/library/ms686967.aspx>. nice link, thank you Vincent Torri |
From: Tor L. <tm...@ik...> - 2007-06-15 19:17:06
|
Brian Dessent writes: > WaitForMultipleObjects() is the Win32 API analogue to unix select. > However remember that it's working on the Win32 level so it takes > handles not fds. You can use the _getosfhandle() function to get the > underlying handle of a fd. But HANDLEs to pipes (anonymous ones, which is what pipe() creates), or files (other than consoles) are not waitiable objects, unfortunately. Windows isn't said to suck for no reason ;) --tml |
From: Tor L. <tm...@ik...> - 2007-06-15 19:14:46
|
Vincent Torri writes: > I've seen that select() is available in winsock2.h, but for sockets True. Sockets only. Not pipes or other file descriptors, which are C library objects. > Is it possible to create 2 sockets (named fd1 and fd2, to fix ideas), the > former for l1, the latter for l2, to link them (like pipe() does), You mean a so called socket pair. Yes. I should have code to create a connected TCP socket pair somewhere, lemme see.... Here: int fake_socketpair(int *fds) { SOCKET temp, socket1 = -1, socket2 = -1; struct sockaddr_in saddr; int len; u_long arg; fd_set read_set, write_set; struct timeval tv; temp = socket (AF_INET, SOCK_STREAM, 0); if (temp == INVALID_SOCKET) { goto out0; } arg = 1; if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR) { goto out0; } memset (&saddr, 0, sizeof (saddr)); saddr.sin_family = AF_INET; saddr.sin_port = 0; saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr))) { goto out0; } if (listen (temp, 1) == SOCKET_ERROR) { goto out0; } len = sizeof (saddr); if (getsockname (temp, (struct sockaddr *)&saddr, &len)) { goto out0; } socket1 = socket (AF_INET, SOCK_STREAM, 0); if (socket1 == INVALID_SOCKET) { goto out0; } arg = 1; if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) { goto out1; } if (connect (socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR || WSAGetLastError () != WSAEWOULDBLOCK) { goto out1; } FD_ZERO (&read_set); FD_SET (temp, &read_set); tv.tv_sec = 0; tv.tv_usec = 0; if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) { goto out1; } if (!FD_ISSET (temp, &read_set)) { goto out1; } socket2 = accept (temp, (struct sockaddr *) &saddr, &len); if (socket2 == INVALID_SOCKET) { goto out1; } FD_ZERO (&write_set); FD_SET (socket1, &write_set); tv.tv_sec = 0; tv.tv_usec = 0; if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) { goto out2; } if (!FD_ISSET (socket1, &write_set)) { goto out2; } arg = 0; if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) { goto out2; } arg = 0; if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) { goto out2; } fds[0] = socket1; fds[1] = socket2; closesocket (temp); return 0; out2: closesocket (socket2); out1: closesocket (socket1); out0: closesocket (temp); errno = EMFILE; /* FIXME: use the real syscall errno? */ fds[0] = -1; fds[1] = -1; return -1; } I think that code works... No guarantees, it's been a while since I wrote it, and I don't recall how much testing that function actually got. --tml |
From: Vincent T. <vt...@un...> - 2007-06-23 09:51:36
|
On Fri, 15 Jun 2007, Tor Lillqvist wrote: > Vincent Torri writes: > > I've seen that select() is available in winsock2.h, but for sockets > > True. Sockets only. Not pipes or other file descriptors, which are C > library objects. > > > Is it possible to create 2 sockets (named fd1 and fd2, to fix ideas), the > > former for l1, the latter for l2, to link them (like pipe() does), > > You mean a so called socket pair. Yes. I should have code to create a > connected TCP socket pair somewhere, lemme see.... Here: > > int fake_socketpair(int *fds) > { > **** > } Hey, I've tried to use it without success. Maybe I don't understand well ho to use it. Do you have a small example of use of fake_socket_pair() with the select() function, please ? thank you Vincent Torri |
From: Vincent T. <vt...@un...> - 2007-06-23 11:31:01
|
On Sat, 23 Jun 2007, Vincent Torri wrote: > > > On Fri, 15 Jun 2007, Tor Lillqvist wrote: > > Hey, > > I've tried to use it without success. Maybe I don't understand well ho to use > it. > > Do you have a small example of use of fake_socket_pair() with the select() > function, please ? Actually, select() blocks forever. The socket is the correct one. I use: ret = select(max_fd + 1, &rfds, &wfds, &exfds, t); with max_fd being one of the socket returned by fake_socket_pair, rfds set by FD_SET, wfds and exfds set by FD_ZERO and t being NULL. So indeed, select() can block forever. I would just like to know why. Is there something specific with the windows sockets ? Vincent Torri |
From: Vincent T. <vt...@un...> - 2007-06-23 14:04:21
|
On Sat, 23 Jun 2007, Vincent Torri wrote: > I've tried to use it without success. Maybe I don't understand well ho > to use it. > > Do you have a small example of use of fake_socket_pair() with the select() > function, please ? I've written a test code below and select() also blocks. Is there something wrong in it, or in fake_socket_pair ? Vincent Torri #include <stdio.h> #include <unistd.h> #include <errno.h> #include <winsock2.h> #define FDREAD 0 #define FDWRITE 1 int main (int argc, char *argv[]) { int sockets[2]; WSADATA version_data; int *i; void *buf[1]; int ret; fd_set rfds; FD_ZERO(&rfds); WSAStartup(MAKEWORD(2, 2), &version_data); if (fake_socketpair(sockets) < 0) { printf ("error\n"); return -1; } FD_SET(sockets[FDREAD], &rfds); i = (int *)malloc(sizeof (int)); *i = 1; buf[0] = i; write(sockets[FDWRITE], buf, sizeof(buf)); printf (" * select : select %d %d\n", sockets[0], sockets[1]); ret = select(sockets[FDREAD] + 1, &rfds, NULL, NULL, NULL); printf (" * select : ret %d\n", ret); if (ret < 0) return -1; if (ret > 0) { int len; int *j = 0; printf ("bon \n"); while ((len = read(sockets[FDREAD], buf, sizeof(buf))) > 0) { if (len == sizeof(buf)) { j = buf[0]; printf ("reussite : %d\n", *j); } } } return 0; } |
From: Tor L. <tm...@ik...> - 2007-06-23 18:21:56
|
Vincent Torri writes: > Is there something wrong in it, or in fake_socket_pair ? > write(sockets[FDWRITE], buf, sizeof(buf)); Bzzt. write() is only for file handles from the C library. For sockets you have to use send() or WSASend(). Even if you had checked the return value from write() you would not necessarily had noticed this bug, because WinSock sockets might well be small integers that overlap valid file descriptors... > while ((len = read(sockets[FDREAD], buf, sizeof(buf))) > 0) Ditto. Use recv() or WSARecv(). Yeah, this means you need ifdefs if this is code intended to be used on both POSIX and Win32, and it uses pipe() on POSIX. (If you use socketpair() on POSIX, you can use send() and recv() there as well.) --tml |
From: Tor L. <tm...@ik...> - 2007-06-23 18:06:00
|
Vincent Torri writes: > I've tried to use it without success. Maybe I don't understand well ho > to use it. > Do you have a small example of use of fake_socket_pair() with the select() > function, please ? Sorry, no. The function was taken from a very large software package, which I actually don't even work on any longer... But anyway, the fake_socketpair() function creates two TCP sockets that are connected to eachother. What you write to one socket (Note: with send(), not write()) can be read from the other (with recv()), and vice versa. The sockets should be usable like any sockets in select(). --tml |
From: Vincent T. <vt...@un...> - 2007-06-15 20:03:20
|
On Fri, 15 Jun 2007, Tor Lillqvist wrote: > Vincent Torri writes: > > I've seen that select() is available in winsock2.h, but for sockets > > True. Sockets only. Not pipes or other file descriptors, which are C > library objects. > > > Is it possible to create 2 sockets (named fd1 and fd2, to fix ideas), the > > former for l1, the latter for l2, to link them (like pipe() does), > > You mean a so called socket pair. maybe ;) I don't really know (I'm a linux coder, actually) > Yes. I should have code to create a > connected TCP socket pair somewhere, lemme see.... Here: Thank you very much. I'll investigate that way. Vincent |
From: Tor L. <tm...@ik...> - 2007-06-15 20:10:39
|
Vincent Torri writes: > > You mean a so called socket pair. > maybe ;) I don't really know (I'm a linux coder, actually) Well, socketpair() is a Unix system call ;) See man socketpair. On Unix it typically is used to create a pair of connected Unix domain sockets, though, not TCP sockets. --tml |
From: Vincent T. <vt...@un...> - 2007-06-20 17:52:40
|
On Fri, 15 Jun 2007, Tor Lillqvist wrote: > Vincent Torri writes: > > I've seen that select() is available in winsock2.h, but for sockets > > True. Sockets only. Not pipes or other file descriptors, which are C > library objects. > > > Is it possible to create 2 sockets (named fd1 and fd2, to fix ideas), the > > former for l1, the latter for l2, to link them (like pipe() does), > > You mean a so called socket pair. Yes. I should have code to create a > connected TCP socket pair somewhere, lemme see.... Here: > I've just tried your function and the first call of socket() fails. Do you know a reason why socket() can't create a socket ? Vincent Torri > int fake_socketpair(int *fds) > { > SOCKET temp, socket1 = -1, socket2 = -1; > struct sockaddr_in saddr; > int len; > u_long arg; > fd_set read_set, write_set; > struct timeval tv; > > temp = socket (AF_INET, SOCK_STREAM, 0); > > if (temp == INVALID_SOCKET) { > goto out0; > } > > arg = 1; > if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR) { > goto out0; > } > > memset (&saddr, 0, sizeof (saddr)); > saddr.sin_family = AF_INET; > saddr.sin_port = 0; > saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); > > if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr))) { > goto out0; > } > > if (listen (temp, 1) == SOCKET_ERROR) { > goto out0; > } > > len = sizeof (saddr); > if (getsockname (temp, (struct sockaddr *)&saddr, &len)) { > goto out0; > } > > socket1 = socket (AF_INET, SOCK_STREAM, 0); > > if (socket1 == INVALID_SOCKET) { > goto out0; > } > > arg = 1; > if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) { > goto out1; > } > > if (connect (socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR || > WSAGetLastError () != WSAEWOULDBLOCK) { > goto out1; > } > > FD_ZERO (&read_set); > FD_SET (temp, &read_set); > > tv.tv_sec = 0; > tv.tv_usec = 0; > > if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) { > goto out1; > } > > if (!FD_ISSET (temp, &read_set)) { > goto out1; > } > > socket2 = accept (temp, (struct sockaddr *) &saddr, &len); > if (socket2 == INVALID_SOCKET) { > goto out1; > } > > FD_ZERO (&write_set); > FD_SET (socket1, &write_set); > > tv.tv_sec = 0; > tv.tv_usec = 0; > > if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) { > goto out2; > } > > if (!FD_ISSET (socket1, &write_set)) { > goto out2; > } > > arg = 0; > if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) { > goto out2; > } > > arg = 0; > if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) { > goto out2; > } > > fds[0] = socket1; > fds[1] = socket2; > > closesocket (temp); > > return 0; > > out2: > closesocket (socket2); > out1: > closesocket (socket1); > out0: > closesocket (temp); > errno = EMFILE; /* FIXME: use the real syscall errno? */ > > fds[0] = -1; > fds[1] = -1; > > return -1; > } > > I think that code works... No guarantees, it's been a while since I > wrote it, and I don't recall how much testing that function actually > got. > > --tml > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 express and take > control of your XML. No limits. Just data. Click to get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > MinGW-users mailing list > Min...@li... > > You may change your MinGW Account Options or unsubscribe at: > https://lists.sourceforge.net/lists/listinfo/mingw-users > > -- > Ce message a été vérifié par MailScanner > pour des virus ou des polluriels et rien de > suspect n'a été trouvé. > Message délivré par le serveur de messagerie de l'Université d'Evry. > > |
From: Tor L. <tm...@ik...> - 2007-06-20 17:55:51
|
Vincent Torri writes: > I've just tried your function and the first call of socket() fails. Do you > know a reason why socket() can't create a socket ? You haven't called WSAStartup()? Check the error code from WSAGetLastError(). --tml |
From: Vincent T. <vt...@un...> - 2007-06-20 18:31:56
|
On Wed, 20 Jun 2007, Tor Lillqvist wrote: > Vincent Torri writes: > > I've just tried your function and the first call of socket() fails. Do you > > know a reason why socket() can't create a socket ? > > You haven't called WSAStartup()? Check the error code from WSAGetLastError(). You are right, I didn't call it. Thank you Vincent Torri |
From: Brian D. <br...@de...> - 2007-06-20 17:58:18
|
Vincent Torri wrote: > I've just tried your function and the first call of socket() fails. Do you > know a reason why socket() can't create a socket ? Did you initialize Winsock? Brian |
From: Tuomo L. <dj...@ik...> - 2007-06-25 08:48:17
|
Tor Lillqvist wrote: > Vincent Torri writes: > > Is there something wrong in it, or in fake_socket_pair ? > > > write(sockets[FDWRITE], buf, sizeof(buf)); > > Bzzt. write() is only for file handles from the C library. For sockets > you have to use send() or WSASend(). > > Even if you had checked the return value from write() you would not > necessarily had noticed this bug, because WinSock sockets might well > be small integers that overlap valid file descriptors... Well, actually you would have got -1 as return value, a clear indication of error. Then errno being EBADF, you would have seen that there was something very wrong with the handle. http://msdn2.microsoft.com/en-us/library/aa273406(VS.60).aspx -- Tuomo ... From the Department of Redundancy Dept. |
From: Tor L. <tm...@ik...> - 2007-06-25 09:29:36
|
I wrote: > > Even if you had checked the return value from write() you would not > > necessarily had noticed this bug, because WinSock sockets might well > > be small integers that overlap valid file descriptors... Tuomo Latto writes: > Well, actually you would have got -1 as return value, a clear indication > of error. Then errno being EBADF, you would have seen that there was > something very wrong with the handle. Think again. Nothing prevents a SOCKET from having the same value as a currently open file descriptor. Try the below test program and you will notice that you also get SOCKETs that are smallish integers that are also file descriptors. (If the program doesn't print "Overlap", try increasing the NSOCK value.) Sure, at least for me, only after having several hundred sockets open do the SOCKET numbers get down to around a hundred, so overlaps won't probably happen in small personal applications that have just a handful of files and a handful of sockets open. But that just makes the risk much larger, as this then means you won't necessarily notice the problem in small scale tests, but then when you deploy some client/server app in production use with dozens of clients connecting and disconnecting all the time, boom! --tml #include <stdio.h> #include <errno.h> #include <io.h> #include <fcntl.h> #include <winsock2.h> #define NFD 100 #define NSOCK 1000 int main (int argc, char **argv) { int fd[NFD]; char fname[NFD]; int i, j; WSADATA wsadata; SOCKET sock; if (WSAStartup (MAKEWORD (2, 0), &wsadata)) fprintf (stderr, "WSAStartup() failed: %d\n", WSAGetLastError ()), exit (1); for (i = 0; i < NFD; i++) { sprintf (fname, "foo%04d.tmp", i); fd[i] = open (fname, _O_CREAT|_O_WRONLY|_O_BINARY|_O_TEMPORARY, 0666); if (fd[i] == -1) fprintf (stderr, "open(%s) failed: %d\n", fname, errno); } for (j = 0; j < NSOCK; j++) { sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock == INVALID_SOCKET) fprintf (stderr, "socket() failed: %d\n", WSAGetLastError ()), exit (1); printf ("%d ", sock); fflush (stdout); for (i = 0; i < NFD; i++) if (sock == fd[i]) { printf ("\nOverlap at %d after creating %d sockets\n", sock, j+1); exit (0); } } return 0; } |