public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* Opening a socket connection in a fork ?
@ 2009-09-16 20:16 Gu1ll4um3r0m41n
  2009-09-22 14:24 ` Corinna Vinschen
  0 siblings, 1 reply; 2+ messages in thread
From: Gu1ll4um3r0m41n @ 2009-09-16 20:16 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 631 bytes --]

Hello,
I'm trying to run a program on cygwin that forks, opens a socket
connection and sends the status of the connection to the parent
process using pipes. The parent process then sends data through the
opened socket.
The program works well on linux but on cygwin, i cannot use recv on a
socket opened in a fork. The recv function always return -1, errno 22
("EINVAL").
The weird thing is that the socket stays open and send still works...

I attached a short example.
I don't know if this is a bug or a limitation due to the fork()
implementation in cygwin... I searched on google but couldn't find
anything really useful.


Gu1

[-- Attachment #2: test.c --]
[-- Type: application/octet-stream, Size: 2522 bytes --]

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>

struct sdata {
	int child_read;
	int child_write;
	int sock;
};

void openConnection(struct sdata *data) {
	struct sockaddr_in *address;
	address = malloc(sizeof(*data));
	memset(address, 0, sizeof(*data));
	char result[2];
	
	address->sin_addr.s_addr = inet_addr("74.125.45.100"); // google ip address
	address->sin_port = htons(80);
	address->sin_family = AF_INET;
	
	if (connect(data->sock, (struct sockaddr*)address, sizeof(*address)) == 0) {
		result[0] = '0';
	} else {
		result[0] = '3';
	}
	write(data->child_write, result, 2);
}

void waitResult(struct sdata *data) {
	fd_set read_fds;
	struct timeval tv_timeout;
	int max_fd, ready;
	char buf[20];
	char httpresult[4096];
	
	while(1) {
		FD_ZERO(&read_fds);
		FD_SET(data->child_read, &read_fds);
		tv_timeout.tv_sec = 2;
		tv_timeout.tv_usec = 0;
		
		ready = select (data->child_read+1, &read_fds, NULL, NULL, &tv_timeout);
		
		if(ready > 0) {
			read(data->child_read, buf, 10);
			break;
		} else {
			printf("no data in 2secs\r\n");
		}
	}
	if(buf[0] == '0') {
		printf("connection ok !\r\n");
		send(data->sock, "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", strlen("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n"), 0);
		int coder = recv(data->sock, httpresult, 4096, 0);
		printf("%i > %i\r\n", coder, errno);
	} else {
		printf("connection could not be etablished\r\n");
	}
}

int init(struct sdata *data) {
	int child_pipe[2];
	if (pipe (child_pipe) < 0) {
		printf("unable to create pipe");
		return 0;
	}
	data->child_read = child_pipe[0];
	data->child_write = child_pipe[1];
	
	data->sock = socket(AF_INET, SOCK_STREAM, 0);
	
	return 1;
}

int main() {
	struct sdata *data;
	pid_t pid;
	data = malloc(sizeof(*data));
	
	if(init(data) < 1) {
		return 0;
	}
	
	/*****/
	switch(pid = fork()) {
		/* fork failed */
		case -1:
			printf("fork failed");
			return;
		/* child process */
		case 0:
			setuid(getuid());
			close(data->child_read);
			openConnection(data);
			_exit(EXIT_SUCCESS);
	}
	
	waitResult(data); // won't work: openConnection is inside a fork
	
	close(data->child_read);
	close(data->child_write);
	close(data->sock);
	
	/*****/
	
	if(init(data) < 1) {
		return 0;
	}
	
	openConnection(data);
	waitResult(data); // will work
	
	close(data->child_read);
	close(data->child_write);
	close(data->sock);
	
	return 0;
}

[-- Attachment #3: Type: text/plain, Size: 218 bytes --]

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Opening a socket connection in a fork ?
  2009-09-16 20:16 Opening a socket connection in a fork ? Gu1ll4um3r0m41n
@ 2009-09-22 14:24 ` Corinna Vinschen
  0 siblings, 0 replies; 2+ messages in thread
From: Corinna Vinschen @ 2009-09-22 14:24 UTC (permalink / raw)
  To: cygwin

On Sep 16 22:16, Gu1ll4um3r0m41n wrote:
> Hello,
> I'm trying to run a program on cygwin that forks, opens a socket
> connection and sends the status of the connection to the parent
> process using pipes. The parent process then sends data through the
> opened socket.
> The program works well on linux but on cygwin, i cannot use recv on a
> socket opened in a fork. The recv function always return -1, errno 22
> ("EINVAL").
> The weird thing is that the socket stays open and send still works...
> 
> I attached a short example.
> I don't know if this is a bug or a limitation due to the fork()
> implementation in cygwin... I searched on google but couldn't find
> anything really useful.

It looks like a really weird problem in WinSock.  Cygwin doesn't do
anything special in this case.

The socket handle gets duplicated into the child process on fork.  The
child calls connect on the duplicated socket handle which apparently
succeeds.

In this scenario, calls to WinSock's recvfrom and WSARecvFrom in the
parent will fail with WSAEINVAL, regardless whether both address
parameters, name and namelen, are NULL or point to valid storage.
However, calls to recv and WSARecv succeed as expected.

Per MSDN, WSAEINVAL in the context of recv means  "The socket has not
been bound".  It is as if the recvfrom functions test if the socket is
bound locally, but in the parent process, WinSock doesn't know about
that and fails, while the same test is omitted in the recv functions.

The same problem does not exist for sendto/WSASendTo apparently.

I'm going to apply a patch which calls WSARecv rather than WSARecvFrom
if the name parameter is NULL.  This fixes the above problem and, given
that the `!wsamsg->name' check has to be called anyway to workaround
another WinSock problem, has no performance hit.

I also created a native Win32 testcase which proves that this isn't a
Cygwin problem, but a WinSock problem.


Thanks for the report,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-09-22 14:24 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-16 20:16 Opening a socket connection in a fork ? Gu1ll4um3r0m41n
2009-09-22 14:24 ` Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).