/** * Dispatches an AFC packet over a client. * * @param client The client to send data through. * @param operation The operation to perform. * @param data The data to send together with the header. * @param data_length The length of the data to send with the header. * @param payload The data to send after the header has been sent. * @param payload_length The length of data to send after the header. * @param bytes_sent The total number of bytes actually sent. * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, const char *data, uint32_t data_length, const char* payload, uint32_t payload_length, uint32_t *bytes_sent) { uint32_t sent = 0; if (!client || !client->parent || !client->afc_packet) return AFC_E_INVALID_ARG; *bytes_sent = 0; if (!data || !data_length) data_length = 0; if (!payload || !payload_length) payload_length = 0; client->afc_packet->packet_num++; client->afc_packet->operation = operation; client->afc_packet->entire_length = sizeof(AFCPacket) + data_length + payload_length; client->afc_packet->this_length = sizeof(AFCPacket) + data_length; debug_info("packet length = %i", client->afc_packet->this_length); debug_buffer((char*)client->afc_packet, sizeof(AFCPacket)); /* send AFC packet header */ AFCPacket_to_LE(client->afc_packet); sent = 0; service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket), &sent); AFCPacket_from_LE(client->afc_packet); *bytes_sent += sent; if (sent < sizeof(AFCPacket)) { return AFC_E_SUCCESS; } /* send AFC packet data (if there's data to send) */ sent = 0; if (data_length > 0) { debug_info("packet data follows"); debug_buffer(data, data_length); service_send(client->parent, data, data_length, &sent); } *bytes_sent += sent; if (sent < data_length) { return AFC_E_SUCCESS; } sent = 0; if (payload_length > 0) { debug_info("packet payload follows"); debug_buffer(payload, payload_length); service_send(client->parent, payload, payload_length, &sent); } *bytes_sent += sent; if (sent < payload_length) { return AFC_E_SUCCESS; } return AFC_E_SUCCESS; }
void handle_connect(FILE* sock, const char* args) { // Attempt to autoconfigure, if there is no current configuration service_send(&service_write_ibuf, WRITE_AUTOCONFIGURE, args); service_pop(&service_write_ibuf, NULL, 0); service_send(&service_exec_ibuf, EXEC_NETSTART, args); int32_t result = service_pop(&service_exec_ibuf, NULL, 0); if(result == EXEC_RESPONSE_OK) { flatjson_send_singleton(sock, "ok"); } else { flatjson_send_singleton(sock, "error"); } fputs("\n", sock); }
/** * Send binary data to the device. * * @note This function returns MOBILEBACKUP2_E_SUCCESS even if less than the * requested length has been sent. The fourth parameter is required and * must be checked to ensure if the whole data has been sent. * * @param client The MobileBackup client to send to. * @param data Pointer to the data to send * @param length Number of bytes to send * @param bytes Number of bytes actually sent * * @return MOBILEBACKUP2_E_SUCCESS if any data was successfully sent, * MOBILEBACKUP2_E_INVALID_ARG if one of the parameters is invalid, * or MOBILEBACKUP2_E_MUX_ERROR if sending of the data failed. */ mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, const char *data, uint32_t length, uint32_t *bytes) { if (!client || !client->parent || !data || (length == 0) || !bytes) return MOBILEBACKUP2_E_INVALID_ARG; *bytes = 0; service_client_t raw = client->parent->parent->parent; int bytes_loc = 0; uint32_t sent = 0; do { bytes_loc = 0; service_send(raw, data+sent, length-sent, (uint32_t*)&bytes_loc); if (bytes_loc <= 0) break; sent += bytes_loc; } while (sent < length); if (sent > 0) { *bytes = sent; return MOBILEBACKUP2_E_SUCCESS; } else { return MOBILEBACKUP2_E_MUX_ERROR; } }
void service_log(uint32_t handle, const char *fmt, ...) { if (g.log == 0) { fprintf(stderr, "[%u] ", handle); va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } else { struct message m; int size; va_list ap; va_start(ap, fmt); size = vsnprintf(0, 0, fmt, ap); va_end(ap); m.data = service_alloc(0, size+1); va_start(ap, fmt); vsnprintf((char *)m.data, size+1, fmt, ap); va_end(ap); m.size = size+1; m.session = 0; m.proto = 0; m.source = handle; if (-1 == service_send(g.log, &m)) service_alloc(m.data, 0); } }
void handle_iface_change(int monitor) { char buf[2048]; read(monitor, buf, sizeof(buf)); struct rt_msghdr* rtm = (struct rt_msghdr*)&buf; struct if_msghdr ifm; memcpy(&ifm, rtm, sizeof(ifm)); char iface[IF_NAMESIZE]; if(if_indextoname(ifm.ifm_index, iface) == NULL) { warn("Failed to look up iface by index"); return; } bool up = LINK_STATE_IS_UP(ifm.ifm_data.ifi_link_state); const char* term = up? "up" : "down"; snprintf(buf, sizeof(buf), "%s %s", term, iface); service_send(&service_exec_ibuf, EXEC_LOGEVENT, buf); int32_t result = service_pop(&service_exec_ibuf, NULL, 0); if(result != EXEC_RESPONSE_OK) { warn("Failed to log iface change"); return; } }
/** * Sends a plist using the given property list service client. * Internally used generic plist send function. * * @param client The property list service client to use for sending. * @param plist plist to send * @param binary 1 = send binary plist, 0 = send xml plist * * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, * PROPERTY_LIST_SERVICE_E_INVALID_ARG when one or more parameters are * invalid, PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid * plist, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified * error occurs. */ static property_list_service_error_t internal_plist_send(property_list_service_client_t client, plist_t plist, int binary) { property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; char *content = NULL; uint32_t length = 0; uint32_t nlen = 0; int bytes = 0; if (!client || (client && !client->parent) || !plist) { return PROPERTY_LIST_SERVICE_E_INVALID_ARG; } if (binary) { plist_to_bin(plist, &content, &length); } else { plist_to_xml(plist, &content, &length); } if (!content || length == 0) { return PROPERTY_LIST_SERVICE_E_PLIST_ERROR; } nlen = htobe32(length); debug_info("sending %d bytes", length); service_send(client->parent, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); if (bytes == sizeof(nlen)) { service_send(client->parent, content, length, (uint32_t*)&bytes); if (bytes > 0) { debug_info("sent %d bytes", bytes); debug_plist(plist); if ((uint32_t)bytes == length) { res = PROPERTY_LIST_SERVICE_E_SUCCESS; } else { debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length); } } } if (bytes <= 0) { debug_info("ERROR: sending to device failed."); } free(content); return res; }
static void queue_message_dtor(struct message *m, void *ud) { service_alloc(m->data, 0); struct message em; em.source = (uint32_t)(uintptr_t)ud; em.session = 0; em.data = 0; em.size = 0; service_send(m->source, &em); }
static void service_timer_dispatch(void *p) { struct timer_event *evt = (struct timer_event *)p; struct message m; m.source = evt->handle; m.session = evt->session; m.data = 0; m.size = 0; m.proto = SERVICE_PROTO_RESP; service_send(evt->handle, &m); }
int list_pseudo_classes(char* buf, size_t buf_len) { buf[0] = '\0'; service_send(&service_exec_ibuf, EXEC_IFCONFIG_LIST_PSEUDO_INTERFACES, NULL); int32_t result = service_pop(&service_exec_ibuf, buf, buf_len); if(result != EXEC_RESPONSE_OK) { return 1; } return 0; }
void handle_configure(FILE* sock, const char* args) { service_send(&service_write_ibuf, WRITE_WRITE, args); int32_t result = service_pop(&service_write_ibuf, NULL, 0); if(result == WRITE_RESPONSE_OK) { flatjson_send_singleton(sock, "ok"); } else { flatjson_send_singleton(sock, "error"); } fputs("\n", sock); }
void handle_disconnect(FILE* sock, const char* args) { char iface[IF_NAMESIZE]; strlcpy(iface, args, sizeof(iface)); service_send(&service_exec_ibuf, EXEC_IFCONFIG_DOWN, args); int32_t result = service_pop(&service_exec_ibuf, iface, strlen(iface)); if(result == EXEC_RESPONSE_OK) { flatjson_send_singleton(sock, "ok"); } else { flatjson_send_singleton(sock, "error"); } fputs("\n", sock); }
static int service_socket_poll(void) { struct socket_message sm; if (!socket_poll(&sm)) return 0; struct message m; int size = sizeof sm; m.source = 0; m.session = 0; m.data = service_alloc(0, size); m.size = size; m.proto = SERVICE_PROTO_SOCKET; memcpy(m.data, &sm, size); uint32_t handle = (uint32_t)(uintptr_t)sm.ud; if (-1 == service_send(handle, &m)) service_alloc(m.data, 0); return 1; }
int service_timeout(uint32_t handle, int ti) { int session = service_session(handle); if (ti == 0) { struct message m; m.source = handle; m.session = session; m.data = 0; m.size = 0; m.proto = SERVICE_PROTO_RESP; session = service_send(handle, &m); } else { struct timer_event evt; evt.session = session; evt.handle = handle; timer_timeout(ti, &evt, sizeof(evt)); } return session; }
debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent) { debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; int bytes = 0; if (!client || !data || (size == 0)) { return SERVICE_E_INVALID_ARG; } debug_info("sending %d bytes", size); res = debugserver_error(service_send(client->parent, data, size, (uint32_t*)&bytes)); if (bytes <= 0) { debug_info("ERROR: sending to device failed."); } if (sent) { *sent = (uint32_t)bytes; } return res; }
/** * Dispatches an AFC packet over a client. * * @param client The client to send data through. * @param data The data to send. * @param length The length to send. * @param bytes_sent The number of bytes actually sent. * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. * * @warning set client->afc_packet->this_length and * client->afc_packet->entire_length to 0 before calling this. The * reason is that if you set them to different values, it indicates * you want to send the data as two packets. */ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, uint32_t length, uint32_t *bytes_sent) { uint32_t offset = 0; uint32_t sent = 0; if (!client || !client->parent || !client->afc_packet) return AFC_E_INVALID_ARG; *bytes_sent = 0; if (!data || !length) length = 0; client->afc_packet->packet_num++; if (!client->afc_packet->entire_length) { client->afc_packet->entire_length = (length) ? sizeof(AFCPacket) + length : sizeof(AFCPacket); client->afc_packet->this_length = client->afc_packet->entire_length; } if (!client->afc_packet->this_length) { client->afc_packet->this_length = sizeof(AFCPacket); } /* We want to send two segments; buffer+sizeof(AFCPacket) to this_length is the parameters and everything beyond that is the next packet. (for writing) */ if (client->afc_packet->this_length != client->afc_packet->entire_length) { offset = (uint32_t)(client->afc_packet->this_length - sizeof(AFCPacket)); debug_info("Offset: %i", offset); if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { debug_info("Length did not resemble what it was supposed to based on packet"); debug_info("length minus offset: %i", length - offset); debug_info("rest of packet: %i\n", client->afc_packet->entire_length - client->afc_packet->this_length); return AFC_E_INTERNAL_ERROR; } /* send AFC packet header */ AFCPacket_to_LE(client->afc_packet); sent = 0; service_send(client->parent, (const char *)client->afc_packet, sizeof(AFCPacket), &sent); AFCPacket_from_LE(client->afc_packet); if (sent == 0) { /* FIXME: should this be handled as success?! */ return AFC_E_SUCCESS; } *bytes_sent += sent; /* send AFC packet data */ sent = 0; service_send(client->parent, data, offset, &sent); if (sent == 0) { return AFC_E_SUCCESS; } *bytes_sent += sent; debug_info("sent the first now go with the second"); debug_info("Length: %i", length - offset); debug_info("Buffer: "); debug_buffer(data + offset, length - offset); sent = 0; service_send(client->parent, data + offset, length - offset, &sent); *bytes_sent = sent; return AFC_E_SUCCESS; } else { debug_info("doin things the old way"); debug_info("packet length = %i", client->afc_packet->this_length); debug_buffer((char*)client->afc_packet, sizeof(AFCPacket)); /* send AFC packet header */ AFCPacket_to_LE(client->afc_packet); sent = 0; service_send(client->parent, (const char *)client->afc_packet, sizeof(AFCPacket), &sent); AFCPacket_from_LE(client->afc_packet); if (sent == 0) { return AFC_E_SUCCESS; } *bytes_sent += sent; /* send AFC packet data (if there's data to send) */ if (length > 0) { debug_info("packet data follows"); debug_buffer(data, length); service_send(client->parent, data, length, &sent); *bytes_sent += sent; } return AFC_E_SUCCESS; } return AFC_E_INTERNAL_ERROR; }
/** delayer service loop */ static void service_loop(int udp_s, int listen_s, struct ringbuf* ring, struct timeval* delay, struct timeval* reuse, struct sockaddr_storage* srv_addr, socklen_t srv_len, sldns_buffer* pkt) { fd_set rset, rorig; fd_set wset, worig; struct timeval now, wait; int max, have_wait = 0; struct proxy* proxies = NULL; struct tcp_proxy* tcp_proxies = NULL; struct timeval tcp_timeout; tcp_timeout.tv_sec = 120; tcp_timeout.tv_usec = 0; #ifndef S_SPLINT_S FD_ZERO(&rorig); FD_ZERO(&worig); FD_SET(FD_SET_T udp_s, &rorig); FD_SET(FD_SET_T listen_s, &rorig); #endif max = udp_s + 1; if(listen_s + 1 > max) max = listen_s + 1; while(!do_quit) { /* wait for events */ rset = rorig; wset = worig; if(have_wait) verbose(1, "wait for %d.%6.6d", (unsigned)wait.tv_sec, (unsigned)wait.tv_usec); else verbose(1, "wait"); if(select(max, &rset, &wset, NULL, have_wait?&wait:NULL) < 0) { if(errno == EAGAIN || errno == EINTR) continue; fatal_exit("select: %s", strerror(errno)); } /* get current time */ if(gettimeofday(&now, NULL) < 0) { if(errno == EAGAIN || errno == EINTR) continue; fatal_exit("gettimeofday: %s", strerror(errno)); } verbose(1, "process at %u.%6.6u\n", (unsigned)now.tv_sec, (unsigned)now.tv_usec); /* sendout delayed queries to master server (frees up buffer)*/ service_send(ring, &now, pkt, srv_addr, srv_len); /* proxy return replies */ service_proxy(&rset, udp_s, proxies, pkt, &now); /* see what can be received to start waiting */ service_recv(udp_s, ring, pkt, &rorig, &max, &proxies, srv_addr, srv_len, &now, delay, reuse); /* see if there are new tcp connections */ service_tcp_listen(listen_s, &rorig, &max, &tcp_proxies, srv_addr, srv_len, &now, &tcp_timeout); /* service tcp connections */ service_tcp_relay(&tcp_proxies, &now, delay, &tcp_timeout, pkt, &rset, &rorig, &worig); /* see what next timeout is (if any) */ have_wait = service_findwait(&now, &wait, ring, tcp_proxies); } proxy_list_clear(proxies); tcp_proxy_list_clear(tcp_proxies); }
/** * Uploads an image to the device. * * @param client The connected mobile_image_mounter client. * @param image_type Type of image that is being uploaded. * @param image_size Total size of the image. * @param upload_cb Callback function that gets the data chunks for uploading * the image. * @param userdata User defined data for the upload callback function. * * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on succes, or a * MOBILE_IMAGE_MOUNTER_E_* error code otherwise. */ mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata) { if (!client || !image_type || (image_size == 0) || !upload_cb) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; } mobile_image_mounter_lock(client); plist_t result = NULL; plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "Command", plist_new_string("ReceiveBytes")); plist_dict_set_item(dict, "ImageSize", plist_new_uint(image_size)); plist_dict_set_item(dict, "ImageType", plist_new_string(image_type)); mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("Error sending XML plist to device!"); goto leave_unlock; } res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("Error receiving response from device!"); goto leave_unlock; } res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; char* strval = NULL; plist_t node = plist_dict_get_item(result, "Status"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &strval); } if (!strval) { debug_info("Error: Unexpected response received!"); goto leave_unlock; } if (strcmp(strval, "ReceiveBytesAck") != 0) { debug_info("Error: didn't get ReceiveBytesAck but %s", strval); free(strval); goto leave_unlock; } free(strval); size_t tx = 0; size_t bufsize = 65536; unsigned char *buf = (unsigned char*)malloc(bufsize); if (!buf) { debug_info("Out of memory"); res = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; goto leave_unlock; } debug_info("uploading image (%d bytes)", (int)image_size); while (tx < image_size) { size_t remaining = image_size - tx; size_t amount = (remaining < bufsize) ? remaining : bufsize; ssize_t r = upload_cb(buf, amount, userdata); if (r < 0) { debug_info("upload_cb returned %d", (int)r); break; } uint32_t sent = 0; if (service_send(client->parent->parent, (const char*)buf, (uint32_t)r, &sent) != SERVICE_E_SUCCESS) { debug_info("service_send failed"); break; } tx += r; } free(buf); if (tx < image_size) { debug_info("Error: failed to upload image"); goto leave_unlock; } debug_info("image uploaded"); res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("Error receiving response from device!"); goto leave_unlock; } res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; strval = NULL; node = plist_dict_get_item(result, "Status"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &strval); } if (!strval) { debug_info("Error: Unexpected response received!"); goto leave_unlock; } if (strcmp(strval, "Complete") != 0) { debug_info("Error: didn't get Complete but %s", strval); free(strval); goto leave_unlock; } else { res = MOBILE_IMAGE_MOUNTER_E_SUCCESS; } free(strval); leave_unlock: mobile_image_mounter_unlock(client); if (result) plist_free(result); return res; }
void handle_list(FILE* sock, bool details) { char pseudo_classes[PSEUDO_CLASSES_LEN]; if(list_pseudo_classes(pseudo_classes, sizeof(pseudo_classes))) { die("Failed to enumerate pseudo classes"); } char* output_text = malloc(1024 * 1024); if(output_text == NULL) { die("Allocating output buffer failed"); } service_send(&service_exec_ibuf, EXEC_IFCONFIG_LIST_INTERFACES, NULL); int32_t result = service_pop(&service_exec_ibuf, output_text, 1024 * 1024); if(result != EXEC_RESPONSE_OK) { flatjson_send_singleton(sock, "error"); fputs("\n", sock); free(output_text); return; } bool first_message = true; flatjson_start_send(sock); flatjson_send(sock, "ok", &first_message); char* cursor; char iface[IF_NAMESIZE]; bool skipping = false; while((cursor = strsep(&output_text, "\n")) != NULL) { char rendered[IF_NAMESIZE + 10]; char key[IFCONFIG_KEY_LEN]; char flags[FLAGS_LEN]; int mtu; if(parse_ifconfig_header(cursor, iface, flags, &mtu)) { if(iface_is_pseudo(iface, pseudo_classes)) { skipping = true; continue; } else { if(!details) { flatjson_send(sock, iface, &first_message); continue; } skipping = false; } snprintf(rendered, sizeof(rendered), "%s.flags", iface); flatjson_send(sock, rendered, &first_message); flatjson_send(sock, flags, &first_message); snprintf(rendered, sizeof(rendered), "%s.mtu", iface); flatjson_send(sock, rendered, &first_message); snprintf(rendered, sizeof(rendered), "%d", mtu); flatjson_send(sock, rendered, &first_message); continue; } if(!skipping && details && parse_ifconfig_kv(cursor, key, flags)) { snprintf(rendered, sizeof(rendered), "%s.%s", iface, key); flatjson_send(sock, rendered, &first_message); flatjson_send(sock, flags, &first_message); } } flatjson_finish_send(sock); fprintf(sock, "\n"); free(output_text); }