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_VERBOSE
41 #include "log.h"
42
43
44 //------------------------------------------------------------------------------
Connection(void)45 Connection::Connection(void)
46 {
47 connectionData = NULL;
48 // Set invalid socketDescriptor
49 socketDescriptor = -1;
50 }
51
52
53 //------------------------------------------------------------------------------
Connection(int socketDescriptor,sockaddr_un * remote)54 Connection::Connection(int socketDescriptor, sockaddr_un *remote)
55 {
56 assert(NULL != remote);
57 assert(-1 != socketDescriptor);
58
59 this->socketDescriptor = socketDescriptor;
60 this->remote = *remote;
61 connectionData = NULL;
62 }
63
64
65 //------------------------------------------------------------------------------
~Connection(void)66 Connection::~Connection(void)
67 {
68 LOG_V(" closing Connection...");
69 if (socketDescriptor != -1)
70 close(socketDescriptor);
71 LOG_I(" Socket connection closed.");
72 }
73
74
75 //------------------------------------------------------------------------------
connect(const char * dest)76 bool Connection::connect(const char *dest)
77 {
78 int32_t len;
79
80 assert(NULL != dest);
81
82 LOG_I(" Connecting to %s socket", dest);
83 remote.sun_family = AF_UNIX;
84 strncpy(remote.sun_path, dest, sizeof(remote.sun_path) - 1);
85 if ((socketDescriptor = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
86 LOG_ERRNO("Can't open stream socket.");
87 return false;
88 }
89 len = strlen(remote.sun_path) + sizeof(remote.sun_family);
90 // The Daemon socket is in the Abstract Domain(LINUX ONLY!)
91 remote.sun_path[0] = 0;
92 if (::connect(socketDescriptor, (struct sockaddr *) &remote, len) < 0) {
93 LOG_ERRNO("connect()");
94 return false;
95 }
96 return true;
97 }
98
99
100 //------------------------------------------------------------------------------
readData(void * buffer,uint32_t len)101 size_t Connection::readData(void *buffer, uint32_t len)
102 {
103 return readData(buffer, len, -1);
104 }
105
106
107 //------------------------------------------------------------------------------
readData(void * buffer,uint32_t len,int32_t timeout)108 size_t Connection::readData(void *buffer, uint32_t len, int32_t timeout)
109 {
110 size_t ret = 0;
111 struct timeval tv;
112 struct timeval *ptv = NULL;
113 fd_set readfds;
114
115 assert(NULL != buffer);
116 assert(socketDescriptor != -1);
117
118 if (timeout >= 0) {
119 // Calculate timeout value
120 tv.tv_sec = timeout / 1000;
121 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
122 ptv = &tv;
123 }
124
125 FD_ZERO(&readfds);
126 FD_SET(socketDescriptor, &readfds);
127 ret = select(socketDescriptor + 1, &readfds, NULL, NULL, ptv);
128
129 // check for read error
130 if ((int)ret == -1) {
131 LOG_ERRNO("select");
132 return -1;
133 }
134
135 // Handle case of no descriptor ready
136 if (0 == ret) {
137 LOG_W(" Timeout during select() / No more notifications.");
138 return -2;
139 }
140
141 // one or more descriptors are ready
142
143 // finally check if fd has been selected -> must socketDescriptor
144 if (!FD_ISSET(socketDescriptor, &readfds)) {
145 LOG_ERRNO("no fd is set, select");
146 return ret;
147 }
148
149 ret = recv(socketDescriptor, buffer, len, MSG_DONTWAIT);
150 if (ret == 0) {
151 LOG_V(" readData(): peer orderly closed connection.");
152 }
153
154 return ret;
155 }
156
157
158 //------------------------------------------------------------------------------
writeData(void * buffer,uint32_t len)159 size_t Connection::writeData(void *buffer, uint32_t len)
160 {
161 size_t ret;
162
163 assert(NULL != buffer);
164 assert(-1 != socketDescriptor);
165
166 ret = send(socketDescriptor, buffer, len, 0);
167 if (ret != len) {
168 LOG_ERRNO("could not send all data, because send");
169 LOG_E("ret = %d", ret);
170 ret = -1;
171 }
172
173 return ret;
174 }
175
176
177 //------------------------------------------------------------------------------
waitData(int32_t timeout)178 int Connection::waitData(int32_t timeout)
179 {
180 size_t ret;
181 struct timeval tv;
182 struct timeval *ptv = NULL;
183 fd_set readfds;
184
185 assert(socketDescriptor != -1);
186
187 if (timeout >= 0) {
188 // Calculate timeout value
189 tv.tv_sec = timeout / 1000;
190 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
191 ptv = &tv;
192 }
193
194 FD_ZERO(&readfds);
195 FD_SET(socketDescriptor, &readfds);
196 ret = select(socketDescriptor + 1, &readfds, NULL, NULL, ptv);
197
198 // check for read error
199 if ((int)ret == -1) {
200 LOG_ERRNO("select");
201 return ret;
202 } else if (ret == 0) {
203 LOG_E("select() timed out");
204 return -1;
205 }
206
207 return 0;
208 }
209
210 /** @} */
211