// SPDX-License-Identifier: GPL-2.0-only
/*
 * ionapp_export.c
 *
 * It is a user space utility to create and export android
 * ion memory buffer fd to another process using unix domain socket as IPC.
 * This acts like a server for ionapp_import(client).
 * So, this server has to be started first before the client.
 *
 * Copyright (C) 2017 Pintu Kumar <pintu.ping@gmail.com>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include "ionutils.h"
#include "ipcsocket.h"


void print_usage(int argc, char *argv[])
{
	printf("Usage: %s [-h <help>] [-i <heap id>] [-s <size in bytes>]\n",
		argv[0]);
}

int main(int argc, char *argv[])
{
	int opt, ret, status, heapid;
	int sockfd, client_fd, shared_fd;
	unsigned char *map_buf;
	unsigned long map_len, heap_type, heap_size, flags;
	struct ion_buffer_info info;
	struct socket_info skinfo;

	if (argc < 2) {
		print_usage(argc, argv);
		return -1;
	}

	heap_size = 0;
	flags = 0;
	heap_type = ION_HEAP_TYPE_SYSTEM;

	while ((opt = getopt(argc, argv, "hi:s:")) != -1) {
		switch (opt) {
		case 'h':
			print_usage(argc, argv);
			exit(0);
			break;
		case 'i':
			heapid = atoi(optarg);
			switch (heapid) {
			case 0:
				heap_type = ION_HEAP_TYPE_SYSTEM;
				break;
			case 1:
				heap_type = ION_HEAP_TYPE_SYSTEM_CONTIG;
				break;
			default:
				printf("ERROR: heap type not supported\n");
				exit(1);
			}
			break;
		case 's':
			heap_size = atoi(optarg);
			break;
		default:
			print_usage(argc, argv);
			exit(1);
			break;
		}
	}

	if (heap_size <= 0) {
		printf("heap_size cannot be 0\n");
		print_usage(argc, argv);
		exit(1);
	}

	printf("heap_type: %ld, heap_size: %ld\n", heap_type, heap_size);
	info.heap_type = heap_type;
	info.heap_size = heap_size;
	info.flag_type = flags;

	/* This is server: open the socket connection first */
	/* Here; 1 indicates server or exporter */
	status = opensocket(&sockfd, SOCKET_NAME, 1);
	if (status < 0) {
		fprintf(stderr, "<%s>: Failed opensocket.\n", __func__);
		goto err_socket;
	}
	skinfo.sockfd = sockfd;

	ret = ion_export_buffer_fd(&info);
	if (ret < 0) {
		fprintf(stderr, "FAILED: ion_get_buffer_fd\n");
		goto err_export;
	}
	client_fd = info.ionfd;
	shared_fd = info.buffd;
	map_buf = info.buffer;
	map_len = info.buflen;
	write_buffer(map_buf, map_len);

	/* share ion buf fd with other user process */
	printf("Sharing fd: %d, Client fd: %d\n", shared_fd, client_fd);
	skinfo.datafd = shared_fd;
	skinfo.buflen = map_len;

	ret = socket_send_fd(&skinfo);
	if (ret < 0) {
		fprintf(stderr, "FAILED: socket_send_fd\n");
		goto err_send;
	}

err_send:
err_export:
	ion_close_buffer_fd(&info);

err_socket:
	closesocket(sockfd, SOCKET_NAME);

	return 0;
}
