Connection.cpp revision 4e9e8c9c0169b40318386436d762c3d73cf4c328
1/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
2 * @{
3 * @file
4 *
5 * Connection data.
6 *
7 * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 *    products derived from this software without specific prior
19 *    written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33#include <unistd.h>
34#include <assert.h>
35#include <cstring>
36#include <errno.h>
37
38#include "Connection.h"
39
40#define LOG_TAG	"McClient"
41#include "log.h"
42
43
44//------------------------------------------------------------------------------
45Connection::Connection(
46    void
47) {
48	connectionData = NULL;
49	// Set invalid socketDescriptor
50	socketDescriptor = -1;
51}
52
53
54//------------------------------------------------------------------------------
55Connection::Connection(
56    int           socketDescriptor,
57    sockaddr_un   *remote
58) {
59	assert(NULL != remote);
60	assert(-1 != socketDescriptor);
61
62	this->socketDescriptor = socketDescriptor;
63	this->remote = *remote;
64	connectionData = NULL;
65}
66
67
68//------------------------------------------------------------------------------
69Connection::~Connection(
70    void
71) {
72	LOG_I("%s: Connection closed!", __func__);
73    if (socketDescriptor != -1)
74        close(socketDescriptor);
75}
76
77
78//------------------------------------------------------------------------------
79bool Connection::connect(
80    const char *dest
81) {
82	bool ret = false;
83	int32_t len;
84
85	assert(NULL != dest);
86
87	LOG_I("connect(): Connecting to %s", dest);
88	do {
89		remote.sun_family = AF_UNIX;
90		strncpy(remote.sun_path, dest, sizeof(remote.sun_path) - 1);
91		if ((socketDescriptor = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
92			LOG_E("Can't open stream socket - errno: %d", errno);
93			break;
94		}
95		len = strlen(remote.sun_path) + sizeof(remote.sun_family);
96		// The Daemon socket is in the Abstract Domain(LINUX ONLY!)
97		remote.sun_path[0] = 0;
98		if (::connect(socketDescriptor, (struct sockaddr *) &remote, len) < 0) {
99			LOG_E("connect() failed - errno: %d", errno);
100			break;
101		}
102		ret = true;
103	} while (false);
104
105	return ret;
106}
107
108
109//------------------------------------------------------------------------------
110size_t Connection::readData(
111    void *buffer,
112    uint32_t len
113) {
114    return readData(buffer, len, -1);
115}
116
117
118//------------------------------------------------------------------------------
119size_t Connection::readData(
120    void      *buffer,
121    uint32_t  len,
122    int32_t   timeout
123) {
124	size_t ret;
125	struct timeval tv;
126	struct timeval *ptv = NULL;
127    fd_set readfds;
128
129    assert(NULL != buffer);
130	assert(-1 != socketDescriptor);
131
132    do{
133
134        if(timeout >= 0){
135            // Calculate timeout value
136            tv.tv_sec = timeout/1000;
137            tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
138            ptv = &tv;
139        }
140
141        FD_ZERO(&readfds);
142        FD_SET(socketDescriptor, &readfds);
143        ret = select(socketDescriptor + 1, &readfds, NULL, NULL, ptv);
144
145        // check for read error
146        if (-1 == (int)ret) {
147            LOG_E("readData(): select() failed, ret=%d, errno=%d", ret,errno);
148            break;
149        }
150
151        // Handle case of no descriptor ready
152        if (0 == ret) {
153            LOG_W("readData(): select() timed out");
154            ret = -2;
155            break;
156        }
157
158        // one or more descriptors are ready
159
160        // finally check if fd has been selected -> must socketDescriptor
161        if (!FD_ISSET(socketDescriptor, &readfds))
162        {
163            LOG_E("readData(): failure, errno=%d", errno);
164            break;
165        }
166
167        ret = recv(socketDescriptor, buffer, len, MSG_WAITALL);
168        if(0 == ret)
169        {
170            LOG_I("readData(): peer orderly closed connection.");
171            break;
172        }
173
174    }while(false);
175
176	return ret;
177}
178
179
180//------------------------------------------------------------------------------
181size_t Connection::writeData(
182    void *buffer,
183    uint32_t len
184) {
185	size_t ret;
186
187	assert(NULL != buffer);
188	assert(-1 != socketDescriptor);
189
190    ret = send(socketDescriptor, buffer, len, 0);
191    if (ret != len)
192    {
193        LOG_E( "writeData(): could no send all data, ret=%d, errno: %d", ret,errno);
194        ret = -1;
195    }
196
197    return ret;
198}
199
200/** @} */
201