summaryrefslogtreecommitdiffstats
path: root/src/service.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2013-02-26 17:24:23 +0100
committerGravatar Martin Szulecki2013-02-27 16:18:15 +0100
commitf8066bbf5169b7d7e68771bce677355e33a595c1 (patch)
tree8e8ee0a82c3a363c171c7124884af80a68e7cd08 /src/service.c
parentca23188eaab07d744e9cf85d9bf69ed323e94186 (diff)
downloadlibimobiledevice-f8066bbf5169b7d7e68771bce677355e33a595c1.tar.gz
libimobiledevice-f8066bbf5169b7d7e68771bce677355e33a595c1.tar.bz2
implement base service that all other services inherit from
Diffstat (limited to 'src/service.c')
-rw-r--r--src/service.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/src/service.c b/src/service.c
new file mode 100644
index 0000000..929beff
--- /dev/null
+++ b/src/service.c
@@ -0,0 +1,276 @@
1/*
2 * service.c
3 * generic service implementation.
4 *
5 * Copyright (c) 2013 Nikias Bassen. All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24#include <stdlib.h>
25#include <string.h>
26
27#include "service.h"
28#include "idevice.h"
29#include "debug.h"
30
31/**
32 * Convert an idevice_error_t value to an service_error_t value.
33 * Used internally to get correct error codes.
34 *
35 * @param err An idevice_error_t error code
36 *
37 * @return A matching service_error_t error code,
38 * SERVICE_E_UNKNOWN_ERROR otherwise.
39 */
40static service_error_t idevice_to_service_error(idevice_error_t err)
41{
42 switch (err) {
43 case IDEVICE_E_SUCCESS:
44 return SERVICE_E_SUCCESS;
45 case IDEVICE_E_INVALID_ARG:
46 return SERVICE_E_INVALID_ARG;
47 case IDEVICE_E_SSL_ERROR:
48 return SERVICE_E_SSL_ERROR;
49 default:
50 break;
51 }
52 return SERVICE_E_UNKNOWN_ERROR;
53}
54
55/**
56 * Creates a new service for the specified service descriptor.
57 *
58 * @param device The device to connect to.
59 * @param service The service descriptor returned by lockdownd_start_service.
60 * @param client Pointer that will be set to a newly allocated
61 * service_client_t upon successful return.
62 *
63 * @return SERVICE_E_SUCCESS on success,
64 * SERVICE_E_INVALID_ARG when one of the arguments is invalid,
65 * or SERVICE_E_MUX_ERROR when connecting to the device failed.
66 */
67service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client)
68{
69 if (!device || (service->port == 0) || !client || *client)
70 return SERVICE_E_INVALID_ARG;
71
72 /* Attempt connection */
73 idevice_connection_t connection = NULL;
74 if (idevice_connect(device, service->port, &connection) != IDEVICE_E_SUCCESS) {
75 return SERVICE_E_MUX_ERROR;
76 }
77
78 /* create client object */
79 service_client_t client_loc = (service_client_t)malloc(sizeof(struct service_client_private));
80 client_loc->connection = connection;
81
82 /* enable SSL if requested */
83 if (service->ssl_enabled == 1)
84 service_enable_ssl(client_loc);
85
86 /* all done, return success */
87 *client = client_loc;
88 return SERVICE_E_SUCCESS;
89}
90
91/**
92 * Starts a new service on the specified device with given name and
93 * connects to it.
94 *
95 * @param device The device to connect to.
96 * @param service_name The name of the service to start.
97 * @param client Pointer that will point to a newly allocated service_client_t
98 * upon successful return. Must be freed using service_client_free() after
99 * use.
100 *
101 * @return SERVICE_E_SUCCESS on success, or a SERVICE_E_* error code
102 * otherwise.
103 */
104service_error_t service_start_service(idevice_t device, const char* service_name, service_client_t *client)
105{
106 *client = NULL;
107
108 lockdownd_client_t lckd = NULL;
109 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &lckd, NULL)) {
110 debug_info("Could not create a lockdown client.");
111 return SERVICE_E_START_SERVICE_ERROR;
112 }
113
114 lockdownd_service_descriptor_t service = NULL;
115 lockdownd_start_service(lckd, service_name, &service);
116 lockdownd_client_free(lckd);
117
118 if (service->port <= 0) {
119 debug_info("Could not start service %s!", service_name);
120 return SERVICE_E_START_SERVICE_ERROR;
121 }
122
123 service_error_t res = service_client_new(device, service, client);
124 if (res != SERVICE_E_SUCCESS) {
125 debug_info("Could not connect to service %s! Port: %i, error: %i", service_name, service->port, res);
126 return res;
127 }
128
129 if (service) {
130 lockdownd_service_descriptor_free(service);
131 service = NULL;
132 }
133
134 return SERVICE_E_SUCCESS;
135}
136
137/**
138 * Frees a service instance.
139 *
140 * @param client The service instance to free.
141 *
142 * @return SERVICE_E_SUCCESS on success,
143 * SERVICE_E_INVALID_ARG when client is invalid, or a
144 * SERVICE_E_UNKNOWN_ERROR when another error occured.
145 */
146service_error_t service_client_free(service_client_t client)
147{
148 if (!client)
149 return SERVICE_E_INVALID_ARG;
150
151 service_error_t err = idevice_to_service_error(idevice_disconnect(client->connection));
152 free(client);
153 return err;
154}
155
156/**
157 * Sends data using the given service client.
158 *
159 * @param client The service client to use for sending.
160 * @param data Data to send
161 * @param size Size of the data to send
162 * @param sent Number of bytes sent (can be NULL to ignore)
163 *
164 * @return SERVICE_E_SUCCESS on success,
165 * SERVICE_E_INVALID_ARG when one or more parameters are
166 * invalid, or SERVICE_E_UNKNOWN_ERROR when an unspecified
167 * error occurs.
168 */
169service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent)
170{
171 service_error_t res = SERVICE_E_UNKNOWN_ERROR;
172 int bytes = 0;
173
174 if (!client || (client && !client->connection) || !data || (size == 0)) {
175 return SERVICE_E_INVALID_ARG;
176 }
177
178 debug_info("sending %d bytes", size);
179 res = idevice_to_service_error(idevice_connection_send(client->connection, data, size, (uint32_t*)&bytes));
180 if (bytes <= 0) {
181 debug_info("ERROR: sending to device failed.");
182 }
183 if (sent) {
184 *sent = (uint32_t)bytes;
185 }
186
187 return res;
188}
189
190/**
191 * Receives data using the given service client with specified timeout.
192 *
193 * @param client The service client to use for receiving
194 * @param data Buffer that will be filled with the data received
195 * @param size Number of bytes to receive
196 * @param received Number of bytes received (can be NULL to ignore)
197 * @param timeout Maximum time in milliseconds to wait for data.
198 *
199 * @return SERVICE_E_SUCCESS on success,
200 * SERVICE_E_INVALID_ARG when one or more parameters are
201 * invalid, SERVICE_E_MUX_ERROR when a communication error
202 * occurs, or SERVICE_E_UNKNOWN_ERROR when an unspecified
203 * error occurs.
204 */
205service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
206{
207 service_error_t res = SERVICE_E_UNKNOWN_ERROR;
208 int bytes = 0;
209
210 if (!client || (client && !client->connection) || !data || (size == 0)) {
211 return SERVICE_E_INVALID_ARG;
212 }
213
214 res = idevice_to_service_error(idevice_connection_receive_timeout(client->connection, data, size, (uint32_t*)&bytes, timeout));
215 if (bytes <= 0) {
216 debug_info("could not read data");
217 }
218 if (received) {
219 *received = (uint32_t)bytes;
220 }
221
222 return res;
223}
224
225/**
226 * Receives data using the given service client.
227 *
228 * @param client The service client to use for receiving
229 * @param data Buffer that will be filled with the data received
230 * @param size Number of bytes to receive
231 * @param received Number of bytes received (can be NULL to ignore)
232 *
233 * @return SERVICE_E_SUCCESS on success,
234 * SERVICE_E_INVALID_ARG when one or more parameters are
235 * invalid, SERVICE_E_MUX_ERROR when a communication error
236 * occurs, or SERVICE_E_UNKNOWN_ERROR when an unspecified
237 * error occurs.
238 */
239service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received)
240{
241 return service_receive_with_timeout(client, data, size, received, 10000);
242}
243
244/**
245 * Enable SSL for the given service client.
246 *
247 * @param client The connected service client for that SSL should be enabled.
248 *
249 * @return SERVICE_E_SUCCESS on success,
250 * SERVICE_E_INVALID_ARG if client or client->connection is
251 * NULL, SERVICE_E_SSL_ERROR when SSL could not be enabled,
252 * or SERVICE_E_UNKNOWN_ERROR otherwise.
253 */
254service_error_t service_enable_ssl(service_client_t client)
255{
256 if (!client || !client->connection)
257 return SERVICE_E_INVALID_ARG;
258 return idevice_to_service_error(idevice_connection_enable_ssl(client->connection));
259}
260
261/**
262 * Disable SSL for the given service client.
263 *
264 * @param client The connected service client for that SSL should be disabled.
265 *
266 * @return SERVICE_E_SUCCESS on success,
267 * SERVICE_E_INVALID_ARG if client or client->connection is
268 * NULL, or SERVICE_E_UNKNOWN_ERROR otherwise.
269 */
270service_error_t service_disable_ssl(service_client_t client)
271{
272 if (!client || !client->connection)
273 return SERVICE_E_INVALID_ARG;
274 return idevice_to_service_error(idevice_connection_disable_ssl(client->connection));
275}
276