1/*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
3 * The contents of this file constitute Original Code as defined in and are
4 * subject to the Apple Public Source License Version 1.2 (the 'License').
5 * You may not use this file except in compliance with the License. Please
6 * obtain a copy of the License at http://www.apple.com/publicsource and
7 * read it before using this file.
8 *
9 * This Original Code and all software distributed under the License are
10 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
11 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
12 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
13 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
14 * see the License for the specific language governing rights and
15 * limitations under the License.
16 */
17
18/******************************************************************
19
20	Title  : winscard_msg.c
21	Package: PC/SC Lite
22	Author : David Corcoran
23	Date   : 04/19/01
24	License: Copyright (C) 2001 David Corcoran
25			<corcoran@linuxnet.com>
26	Purpose: This is responsible for client/server transport.
27
28$Id: winscard_msg.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
29
30********************************************************************/
31
32#include <fcntl.h>
33#include <unistd.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <sys/mman.h>
37#include <sys/socket.h>
38#include <sys/time.h>
39#include <sys/un.h>
40#include <sys/ioctl.h>
41#include <errno.h>
42#include <stdio.h>
43#include <time.h>
44#include <string.h>
45#include <stdlib.h>
46
47#include "config.h"
48
49#ifdef PCSC_TARGET_SOLARIS
50#include <sys/filio.h>
51#endif
52
53#include "wintypes.h"
54#include "pcsclite.h"
55#include "winscard.h"
56#include "winscard_msg.h"
57#include "sys_generic.h"
58#include "debuglog.h"
59
60int MSGSendData(int filedes, int blockAmount, const void *data,
61	unsigned int dataSize)
62{
63	/*
64	 * default is success
65	 */
66	int retval = 0;
67	/*
68	 * record the time when we started
69	 */
70	time_t start = time(0);
71	/*
72	 * data to be written
73	 */
74	unsigned char *buffer = (unsigned char *) data;
75	/*
76	 * how many bytes remains to be written
77	 */
78	size_t remaining = dataSize;
79
80	/*
81	 * repeat until all data is written
82	 */
83	while (remaining > 0)
84	{
85		fd_set write_fd;
86		struct timeval timeout;
87		int selret;
88
89		FD_ZERO(&write_fd);
90		FD_SET(filedes, &write_fd);
91
92		timeout.tv_usec = 0;
93		if ((timeout.tv_sec = start + blockAmount - time(0)) < 0)
94		{
95			/*
96			 * we already timed out
97			 */
98			retval = -1;
99			break;
100		}
101
102		selret = select(filedes + 1, NULL, &write_fd, NULL, &timeout);
103
104		/*
105		 * try to write only when the file descriptor is writable
106		 */
107		if (selret > 0)
108		{
109			int written;
110
111			if (!FD_ISSET(filedes, &write_fd))
112			{
113				/*
114				 * very strange situation. it should be an assert really
115				 */
116				retval = -1;
117				break;
118			}
119			written = write(filedes, buffer, remaining);
120
121			if (written > 0)
122			{
123				/*
124				 * we wrote something
125				 */
126				buffer += written;
127				remaining -= written;
128			} else if (written == 0)
129			{
130				/*
131				 * peer closed the socket
132				 */
133				retval = -1;
134				break;
135			} else
136			{
137				/*
138				 * we ignore the signals and socket full situations, all
139				 * other errors are fatal
140				 */
141				if (errno != EINTR && errno != EAGAIN)
142				{
143					retval = -1;
144					break;
145				}
146			}
147		} else if (selret == 0)
148		{
149			/*
150			 * timeout
151			 */
152			retval = -1;
153			break;
154		} else
155		{
156			/*
157			 * ignore signals
158			 */
159			if (errno != EINTR)
160			{
161				DebugLogB
162					("MSGServerProcessEvents: Select returns with failure: %s",
163					strerror(errno));
164				retval = -1;
165				break;
166			}
167		}
168	}
169
170	return retval;
171}
172
173int MSGRecieveData(int filedes, int blockAmount, void *data,
174	unsigned int dataSize)
175{
176	/*
177	 * default is success
178	 */
179	int retval = 0;
180	/*
181	 * record the time when we started
182	 */
183	time_t start = time(0);
184	/*
185	 * buffer where we place the readed bytes
186	 */
187	unsigned char *buffer = (unsigned char *) data;
188	/*
189	 * how many bytes we must read
190	 */
191	size_t remaining = dataSize;
192
193	/*
194	 * repeat until we get the whole message
195	 */
196	while (remaining > 0)
197	{
198		fd_set read_fd;
199		struct timeval timeout;
200		int selret;
201
202		FD_ZERO(&read_fd);
203		FD_SET(filedes, &read_fd);
204
205		timeout.tv_usec = 0;
206		if ((timeout.tv_sec = start + blockAmount - time(0)) < 0)
207		{
208			/*
209			 * we already timed out
210			 */
211			retval = -1;
212			break;
213		}
214
215		selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
216
217		/*
218		 * try to read only when socket is readable
219		 */
220		if (selret > 0)
221		{
222			int readed;
223
224			if (!FD_ISSET(filedes, &read_fd))
225			{
226				/*
227				 * very strange situation. it should be an assert really
228				 */
229				retval = -1;
230				break;
231			}
232			readed = read(filedes, buffer, remaining);
233
234			if (readed > 0)
235			{
236				/*
237				 * we got something
238				 */
239				buffer += readed;
240				remaining -= readed;
241			} else if (readed == 0)
242			{
243				/*
244				 * peer closed the socket
245				 */
246				retval = -1;
247				break;
248			} else
249			{
250				/*
251				 * we ignore the signals and empty socket situations, all
252				 * other errors are fatal
253				 */
254				if (errno != EINTR && errno != EAGAIN)
255				{
256					retval = -1;
257					break;
258				}
259			}
260		} else if (selret == 0)
261		{
262			/*
263			 * timeout
264			 */
265			retval = -1;
266			break;
267		} else
268		{
269			/*
270			 * we ignore signals, all other errors are fatal
271			 */
272			if (errno != EINTR)
273			{
274				DebugLogB
275					("MSGServerProcessEvents: Select returns with failure: %s",
276					strerror(errno));
277				retval = -1;
278				break;
279			}
280		}
281	}
282
283	return retval;
284}
285