delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2003/07/22/16:22:12

Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sources.redhat.com/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sources.redhat.com/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com
Message-ID: <950B6B3FADEC484C8D0AE17EEE55E1FA2E02F1@draco.analogic.com>
From: "Hirsch, Matthew" <MHirsch AT analogic DOT com>
To: "'cygwin AT cygwin DOT com'" <cygwin AT cygwin DOT com>
Subject: PTY read/write problems
Date: Tue, 22 Jul 2003 16:21:48 -0400
MIME-Version: 1.0
Note-from-DJ: This may be spam

------_=_NextPart_000_01C3508E.E11E8E00
Content-Type: text/plain

Hi list,

I'm having trouble sending data back and forth between two processes over a
pseudo terminal.  I'm able to send data from the slave tty to the master pty
without any problem.  However, no data can be read from the slave side of
the pty (tty).  I've attached an example program that demonstrates my
problem.  I compiled it with

gcc ptyrw.c -g -o ptyrw -Wall

I have cygwin version 1.3.22-1 (Curr in setup as of yesterday).

I've attempted to follow the suggestions made in earlier discussions of
pseudo terminals (http://sources.redhat.com/ml/cygwin/2002-11/msg00064.html
for example).  Has anyone written an example of a working pty/tty connection
under Cygwin?  I would appreciate it very much if someone could set me
straight on this.

The output I'm getting with my test program is as follows:

$ ./ptyrw
MASTER: Master Alive: My PID: 232
<< Master writing to Slave >>
*Max Read Size: 2147483647
MASTER: Created master pty: 3
MASTER: Associated Slave: /dev/tty0
MASTER: Forking Slave...
MASTER: Preparing to write: Sleeping for 2 to let slave get set up
SLAVE: Slave Alive: My PID: 128
SLAVE: Setting Session ID
SLAVE: Opening slave end of pty
SLAVE: Preparing to read, sleeping for 5 while master writes
MASTER: Writing "Master Send"
MASTER: Wrote 15 bytes: "Master Send"
MASTER: Sleeping for 10 while slave finishes
SLAVE: Attempting to read from fd 4
READERROR: Data did not become available in 3 seconds
SLAVE: Read Error
SLAVE: Quitting...
MASTER: Quitting...

Whereas in this direction things work as expected:

$ ./ptyrw 1
MASTER: Master Alive: My PID: 1124
<< Slave writing to Master >>
*Max Read Size: 2147483647
MASTER: Created master pty: 3
MASTER: Associated Slave: /dev/tty0
MASTER: Forking Slave...
MASTER: Preparing to read, sleeping for 5 while slave writes
SLAVE: Slave Alive: My PID: 1896
SLAVE: Setting Session ID
SLAVE: Opening slave end of pty
SLAVE: Wrote 15 bytes: "Slave Send"
SLAVE: Sleeping for 10 while master finishes
MASTER: Attempting to read from fd 3
MASTER: Read 7 bytes: "Slave S"
MASTER: Sleeping for 10 while slave finishes
SLAVE: Quitting...
MASTER: Quitting...

The fact that read returns data in blocks of 7 bytes or less seems a bit
cumbersome but not out of spec.

Thank you very much for any suggestions.
Matt Hirsch


------_=_NextPart_000_01C3508E.E11E8E00
Content-Type: application/octet-stream;
	name="ptyrw.c"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="ptyrw.c"

#include <stdio.h>=0A=
#include <unistd.h>=0A=
#include <sys/types.h>=0A=
#include <limits.h>=0A=
//#include <termios.h>=0A=
#include <fcntl.h> /*O_RDWR*/=0A=
#include <errno.h>=0A=
#include <malloc.h>=0A=
#include <stdlib.h>=0A=
#include <string.h>=0A=
#include <sys/select.h>=0A=
=0A=
#define MAXLEN 15=0A=
=0A=
int ptym_open(char *pts_name);=0A=
int ptys_open(int pty, char *pts_name);=0A=
int writepty(int pty, char *data, int len);=0A=
int plainread(int fd, char *data, int len);=0A=
void masterquit(int pty, char* vec);=0A=
void slavequit(int tty, char *vec);=0A=
=0A=
int main(int argc, char *argv[])=0A=
{=0A=
	char *testvec1;=0A=
	char *testvec2;=0A=
	char pts_name[20];=0A=
=0A=
	int pty=3D0, tty=3D0;=0A=
	pid_t slaveproc;=0A=
	int direction;=0A=
	int chars1;=0A=
	int chars2;=0A=
=0A=
	printf("MASTER: Master Alive: My PID: %d\n", getpid());=0A=
=0A=
	/* change direction by adding a command line argument */=0A=
=0A=
	direction =3D (argc =3D=3D 2);=0A=
		/* direction =3D 1 =3D> slave to master*/=0A=
		/* direction =3D 0 =3D> master to slave*/=0A=
	printf("<< %s writing to %s =
>>\n",direction?"Slave":"Master",direction?"Master":"Slave");=0A=
	printf("*Max Read Size: %ld\n",SSIZE_MAX);=0A=
=0A=
	if ((pty =3D ptym_open(pts_name)) < 0){=0A=
		fprintf(stderr, "MASTER: Error Creating pty\n");=0A=
		return 1;=0A=
	}=0A=
	printf("MASTER: Created master pty: %d\nMASTER: Associated Slave: =
%s\n",pty,pts_name);=0A=
	printf("MASTER: Forking Slave...\n");=0A=
=0A=
	if ((slaveproc =3D fork()) < 0){=0A=
		fprintf(stderr, "fork error\n");=0A=
		close(pty);=0A=
		return(1);=0A=
	}else if (slaveproc =3D=3D 0){	/*this is the slave, open the tty, =
etc*/=0A=
		printf("SLAVE: Slave Alive: My PID: %d\n", getpid());=0A=
		printf("SLAVE: Setting Session ID\n");=0A=
		if(setsid() < 0){=0A=
			printf("SLAVE: Error setting Session ID: %s :bailing =
out.\n",strerror(errno));=0A=
			return 1;=0A=
		}=0A=
=0A=
		printf("SLAVE: Opening slave end of pty\n");=0A=
		if((tty =3D ptys_open(pty, pts_name))<0){=0A=
			printf("SLAVE: Error opening slave pty %s: %s\nSLAVE: =
Quitting...\n",pts_name,strerror(errno));=0A=
			return 1;=0A=
		}=0A=
=0A=
                testvec1 =3D (char*)calloc(MAXLEN,sizeof(char)); /* =
allocate mem*/=0A=
		=0A=
		if(testvec1 =3D=3D NULL){=0A=
			fprintf(stderr, "SLAVE: memory allocation error\nSLAVE: =
Quitting...\n");=0A=
			close(tty);=0A=
			return 1;=0A=
		}=0A=
		if(direction){=0A=
			strcpy(testvec1, "Slave Send");=0A=
=0A=
			if((chars1 =3D writepty(tty,testvec1,MAXLEN)) < 0){=0A=
				printf("SLAVE: Write Error: %s\n",strerror(errno));=0A=
				slavequit(tty,testvec1);=0A=
				return 1;=0A=
			}=0A=
=0A=
			printf("SLAVE: Wrote %d bytes: \"%s\"\n",chars1,testvec1);=0A=
		}else{=0A=
			printf("SLAVE: Preparing to read, sleeping for 5 while master =
writes\n");=0A=
			sleep(5);=0A=
			printf("SLAVE: Attempting to read from fd %d\n",tty);=0A=
			if((chars1 =3D plainread(tty,testvec1,MAXLEN)) < 0){=0A=
				printf("SLAVE: Read Error\n");=0A=
				slavequit(tty, testvec1);=0A=
				return 1;=0A=
			}=0A=
			printf("SLAVE: Read %d bytes: \"%s\"\n", chars1, testvec1);=0A=
		} /* direction */=0A=
		printf("SLAVE: Sleeping for 10 while master finishes\n");=0A=
		sleep(10);=0A=
		slavequit(pty, testvec1);=0A=
		return 0;=0A=
	}else{				/*master*/=0A=
                testvec2 =3D (char*)calloc(MAXLEN,sizeof(char)); /* =
allocate mem*/=0A=
=0A=
                if(testvec2 =3D=3D NULL){=0A=
                        fprintf(stderr, "MASTER: memory allocation =
error\n");=0A=
                        close(pty);=0A=
			return 1;=0A=
                }=0A=
		if(!direction){=0A=
			strcpy(testvec2, "Master Send");=0A=
			printf("MASTER: Preparing to write: Sleeping for 2 to let slave get =
set up\n");=0A=
			sleep(2);=0A=
		}=0A=
		if(direction){=0A=
			printf("MASTER: Preparing to read, sleeping for 5 while slave =
writes\n");=0A=
			sleep(5);		/*give slave time to write*/=0A=
			printf("MASTER: Attempting to read from fd %d\n",pty);=0A=
			if((chars2 =3D plainread(pty,testvec2, MAXLEN)) < 0){=0A=
				printf("MASTER: Read Error: \"%s\"\n",strerror(errno));=0A=
				masterquit(pty, testvec2);=0A=
				return 1;=0A=
			}=0A=
			printf("MASTER: Read %d bytes: \"%s\"\n",chars2,testvec2);=0A=
		}else{=0A=
			printf("MASTER: Writing \"%s\"\n",testvec2);=0A=
			if((chars2 =3D writepty(pty, testvec2, MAXLEN))<0){=0A=
				printf("MASTER: Write Error: %s\n",strerror(errno));=0A=
				masterquit(pty, testvec2);=0A=
				return 1;=0A=
			}=0A=
			testvec2[chars2] =3D '\0'; /* show what we wrote */=0A=
			printf("MASTER: Wrote %d bytes: \"%s\"\n",chars2,testvec2);=0A=
		}=0A=
		printf("MASTER: Sleeping for 10 while slave finishes\n");=0A=
		sleep(10);=0A=
		masterquit(pty, testvec2);=0A=
		return 0;=0A=
	}=0A=
}=0A=
=0A=
int ptym_open(char *pts_name)=0A=
{=0A=
	char *ptr;=0A=
	int pty;=0A=
=0A=
	if(!pts_name)=0A=
		exit(1);=0A=
	if ((pty =3D open("/dev/ptmx", O_RDWR)) < 0) {=0A=
		fprintf(stderr,"Unable to open /dev/ptmx");=0A=
		return -1;=0A=
	}=0A=
=0A=
	if (grantpt(pty) =3D=3D -1) {=0A=
		fprintf(stderr,"grantpt");=0A=
		return -2;=0A=
	}=0A=
=0A=
	if (unlockpt(pty) =3D=3D -1) {=0A=
		fprintf(stderr,"unlockpt");=0A=
		return -3;=0A=
	}=0A=
=0A=
	ptr =3D (char*)ptsname(pty);=0A=
	if(!ptr){=0A=
		fprintf(stderr,"ptsname");=0A=
		return -4;=0A=
	}=0A=
=0A=
	strcpy(pts_name,ptr);=0A=
=0A=
	return pty;=0A=
}=0A=
=0A=
int ptys_open(int pty, char *pts_name)=0A=
{=0A=
	int tty;=0A=
=0A=
	if ((tty =3D open(pts_name, O_RDWR)) < 0){=0A=
		close(pty);=0A=
		return -5;=0A=
	}=0A=
	return tty;=0A=
}=0A=
=0A=
int writepty(int pty, char *data, int len)=0A=
{=0A=
	int written=3D0;=0A=
=0A=
	if((written =3D write(pty,data,len))<0)=0A=
		return -1;=0A=
	return written;=0A=
}=0A=
=0A=
int plainread(int fd, char *data, int len)=0A=
{=0A=
	struct timeval timeout;=0A=
	fd_set rfds;=0A=
	int selresult, check;=0A=
=0A=
	FD_ZERO(&rfds);		/* make file descriptor set to watch */=0A=
	FD_SET(fd, &rfds);=0A=
=0A=
  	timeout.tv_sec=3D3;	/* set timeout to 3 seconds */=0A=
 	timeout.tv_usec=3D0;=0A=
=0A=
	selresult =3D select(fd+1,&rfds,NULL,NULL,&timeout); /* check fd, wait =
for 3s */=0A=
	if(selresult < 0){=0A=
		printf("READERROR: %s\n",strerror(errno));=0A=
		return -1;=0A=
	}else if (selresult){=0A=
		check =3D read(fd,data,len);=0A=
		if(check > 0)=0A=
			return check;=0A=
		else{=0A=
			printf("READERROR: %s\n",strerror(errno));=0A=
			return -1;=0A=
		}=0A=
	}else{ /* selresult =3D=3D 0 */=0A=
		printf("READERROR: Data did not become available in 3 seconds\n");=0A=
		return -1;=0A=
	}=0A=
}=0A=
=0A=
void masterquit(int pty, char* vec)=0A=
{=0A=
	printf("MASTER: Quitting...\n");=0A=
=0A=
	close(pty);=0A=
	free(vec);=0A=
=0A=
}=0A=
=0A=
void slavequit(int tty, char *vec)=0A=
{=0A=
	printf("SLAVE: Quitting...\n");=0A=
=0A=
	close(tty);=0A=
	free(vec);=0A=
=0A=
}=0A=


------_=_NextPart_000_01C3508E.E11E8E00
Content-Type: text/plain; charset=us-ascii

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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019