text: /**********************************************************************************/
  /*                           example_btgatt-server.c                              */
  /**********************************************************************************/
  #ifdef HAVE_CONFIG_H
  #include <config.h>
  #endif
  
  #include <stdio.h>
  #include <stdbool.h>
  #include <stdint.h>
  #include <time.h>
  #include <stdlib.h>
  #include <getopt.h>
  #include <unistd.h>
  #include <errno.h>
  
  #include "bluetooth/bluetooth.h"
  #include "bluetooth/hci.h"
  #include "bluetooth/hci_lib.h"
  #include "bluetooth/l2cap.h"
  #include "bluetooth/uuid.h"
  
  #include "src/shared/mainloop.h"
  #include "src/shared/util.h"
  #include "src/shared/att.h"
  #include "src/shared/queue.h"
  #include "src/shared/timeout.h"
  #include "src/shared/gatt-db.h"
  #include "src/shared/gatt-server.h"
  
  
  /***** GATT BASED SERVICE UUIDS **********/
  #define UUID_GAP			0x1800
  #define UUID_GATT			0x1801
  //Add service UUIDS here
  
  /*****************************************/
  
  /***** GATT BASED CHARACTERISTC UUIDS ********/
  
  //Add charcateristic UUIDS here
  
  /*********************************************/
  
  #define ATT_CID 4
  
  #define PRLOG(...) \
  	do { \
  		printf(__VA_ARGS__); \
  		print_prompt(); \
  	} while (0)
  
  #ifndef MIN
  #define MIN(a, b) ((a) < (b) ? (a) : (b))
  #endif
  
  #define COLOR_OFF	"\x1B[0m"
  #define COLOR_RED	"\x1B[0;91m"
  #define COLOR_GREEN	"\x1B[0;92m"
  #define COLOR_YELLOW	"\x1B[0;93m"
  #define COLOR_BLUE	"\x1B[0;94m"
  #define COLOR_MAGENTA	"\x1B[0;95m"
  #define COLOR_BOLDGRAY	"\x1B[1;30m"
  #define COLOR_BOLDWHITE	"\x1B[1;37m"
  
  static const char test_device_name[] = "Very Long Test Device Name For Testing "
  				"ATT Protocol Operations On GATT Server";
  static bool verbose = false;
  
  struct server {
  	int fd;
  	struct bt_att *att;
  	struct gatt_db *db;
  	struct bt_gatt_server *gatt;
  
  	uint8_t *device_name;
  	size_t name_len;
  
  	uint16_t gatt_svc_chngd_handle;
  	bool svc_chngd_enabled;
  };
  
  static void advertise(void)
  {
      int ret;
      ret = system("hciconfig hci0 leadv0");
      /** if required set advertsing data **/
      /** ret = system("hcitool -i hci0 cmd 0x08 0x0008 ..Data.."); **/
  
      /** if required set scan response data ***/
      /** ret = system("hcitool -i hci0 cmd 0x08 0x0009 ..Data.."), **/
  }
  static void print_prompt(void)
  {
  	printf(COLOR_BLUE "[GATT server]" COLOR_OFF "# ");
  	fflush(stdout);
  }
  
  static void att_disconnect_cb(int err, void *user_data)
  {
  	printf("Device disconnected: %s\n", strerror(err));
  
  	mainloop_quit();
  }
  
  static void att_debug_cb(const char *str, void *user_data)
  {
  	const char *prefix = user_data;
  
  	PRLOG(COLOR_BOLDGRAY "%s" COLOR_BOLDWHITE "%s\n" COLOR_OFF, prefix,
  									str);
  }
  
  static void gatt_debug_cb(const char *str, void *user_data)
  {
  	const char *prefix = user_data;
  
  	PRLOG(COLOR_GREEN "%s%s\n" COLOR_OFF, prefix, str);
  }
  
  static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
  					unsigned int id, uint16_t offset,
  					uint8_t opcode, struct bt_att *att,
  					void *user_data)
  {
  	struct server *server = user_data;
  	uint8_t error = 0;
  	size_t len = 0;
  	const uint8_t *value = NULL;
  
  	PRLOG("GAP Device Name Read called\n");
  
  	len = server->name_len;
  
  	if (offset > len) {
  		error = BT_ATT_ERROR_INVALID_OFFSET;
  		goto done;
  	}
  
  	len -= offset;
  	value = len ? &server->device_name[offset] : NULL;
  
  done:
  	gatt_db_attribute_read_result(attrib, id, error, value, len);
  }
  
  static void gap_device_name_write_cb(struct gatt_db_attribute *attrib,
  					unsigned int id, uint16_t offset,
  					const uint8_t *value, size_t len,
  					uint8_t opcode, struct bt_att *att,
  					void *user_data)
  {
  	struct server *server = user_data;
  	uint8_t error = 0;
  
  	PRLOG("GAP Device Name Write called\n");
  
  	/* If the value is being completely truncated, clean up and return */
  	if (!(offset + len)) {
  		free(server->device_name);
  		server->device_name = NULL;
  		server->name_len = 0;
  		goto done;
  	}
  
  	/* Implement this as a variable length attribute value. */
  	if (offset > server->name_len) {
  		error = BT_ATT_ERROR_INVALID_OFFSET;
  		goto done;
  	}
  
  	if (offset + len != server->name_len) {
  		uint8_t *name;
  
  		name = realloc(server->device_name, offset + len);
  		if (!name) {
  			error = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
  			goto done;
  		}
  
  		server->device_name = name;
  		server->name_len = offset + len;
  	}
  
  	if (value)
  		memcpy(server->device_name + offset, value, len);
  
  done:
  	gatt_db_attribute_write_result(attrib, id, error);
  }
  
  static void gap_device_name_ext_prop_read_cb(struct gatt_db_attribute *attrib,
  					unsigned int id, uint16_t offset,
  					uint8_t opcode, struct bt_att *att,
  					void *user_data)
  {
  	uint8_t value[2];
  
  	PRLOG("Device Name Extended Properties Read called\n");
  
  	value[0] = BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
  	value[1] = 0;
  
  	gatt_db_attribute_read_result(attrib, id, 0, value, sizeof(value));
  }
  
  static void gatt_service_changed_cb(struct gatt_db_attribute *attrib,
  					unsigned int id, uint16_t offset,
  					uint8_t opcode, struct bt_att *att,
  					void *user_data)
  {
  	PRLOG("Service Changed Read called\n");
  
  	gatt_db_attribute_read_result(attrib, id, 0, NULL, 0);
  }
  
  static void gatt_svc_chngd_ccc_read_cb(struct gatt_db_attribute *attrib,
  					unsigned int id, uint16_t offset,
  					uint8_t opcode, struct bt_att *att,
  					void *user_data)
  {
  	struct server *server = user_data;
  	uint8_t value[2];
  
  	PRLOG("Service Changed CCC Read called\n");
  
  	value[0] = server->svc_chngd_enabled ? 0x02 : 0x00;
  	value[1] = 0x00;
  
  	gatt_db_attribute_read_result(attrib, id, 0, value, sizeof(value));
  }
  
  static void gatt_svc_chngd_ccc_write_cb(struct gatt_db_attribute *attrib,
  					unsigned int id, uint16_t offset,
  					const uint8_t *value, size_t len,
  					uint8_t opcode, struct bt_att *att,
  					void *user_data)
  {
  	struct server *server = user_data;
  	uint8_t ecode = 0;
  
  	PRLOG("Service Changed CCC Write called\n");
  
  	if (!value || len != 2) {
  		ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
  		goto done;
  	}
  
  	if (offset) {
  		ecode = BT_ATT_ERROR_INVALID_OFFSET;
  		goto done;
  	}
  
  	if (value[0] == 0x00)
  		server->svc_chngd_enabled = false;
  	else if (value[0] == 0x02)
  		server->svc_chngd_enabled = true;
  	else
  		ecode = 0x80;
  
  	PRLOG("Service Changed Enabled: %s\n",
  				server->svc_chngd_enabled ? "true" : "false");
  
  done:
  	gatt_db_attribute_write_result(attrib, id, ecode);
  }
  static void confirm_write(struct gatt_db_attribute *attr, int err,
  							void *user_data)
  {
  	if (!err)
  		return;
  
  	fprintf(stderr, "Error caching attribute %p - err: %d\n", attr, err);
  	exit(1);
  }
  
  static void populate_gap_service(struct server *server)
  {
  	bt_uuid_t uuid;
  	struct gatt_db_attribute *service, *tmp;
  	uint16_t appearance;
  
  	/* Add the GAP service */
  	bt_uuid16_create(&uuid, UUID_GAP);
  	service = gatt_db_add_service(server->db, &uuid, true, 6);
  
  	/*
  	 * Device Name characteristic. Make the value dynamically read and
  	 * written via callbacks.
  	 */
  	bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
  	gatt_db_service_add_characteristic(service, &uuid,
  					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
  					BT_GATT_CHRC_PROP_READ |
  					BT_GATT_CHRC_PROP_EXT_PROP,
  					gap_device_name_read_cb,
  					gap_device_name_write_cb,
  					server);
  
  	bt_uuid16_create(&uuid, GATT_CHARAC_EXT_PROPER_UUID);
  	gatt_db_service_add_descriptor(service, &uuid, BT_ATT_PERM_READ,
  					gap_device_name_ext_prop_read_cb,
  					NULL, server);
  
  	/*
  	 * Appearance characteristic. Reads and writes should obtain the value
  	 * from the database.
  	 */
  	bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
  	tmp = gatt_db_service_add_characteristic(service, &uuid,
  							BT_ATT_PERM_READ,
  							BT_GATT_CHRC_PROP_READ,
  							NULL, NULL, server);
  
  	/*
  	 * Write the appearance value to the database, since we're not using a
  	 * callback.
  	 */
  	put_le16(128, &appearance);
  	gatt_db_attribute_write(tmp, 0, (void *) &appearance,
  							sizeof(appearance),
  							BT_ATT_OP_WRITE_REQ,
  							NULL, confirm_write,
  							NULL);
  
  	gatt_db_service_set_active(service, true);
  }
  
  static void populate_gatt_service(struct server *server)
  {
  	bt_uuid_t uuid;
  	struct gatt_db_attribute *service, *svc_chngd;
  
  	/* Add the GATT service */
  	bt_uuid16_create(&uuid, UUID_GATT);
  	service = gatt_db_add_service(server->db, &uuid, true, 4);
  
  	bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
  	svc_chngd = gatt_db_service_add_characteristic(service, &uuid,
  			BT_ATT_PERM_READ,
  			BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_INDICATE,
  			gatt_service_changed_cb,
  			NULL, server);
  	server->gatt_svc_chngd_handle = gatt_db_attribute_get_handle(svc_chngd);
  
  	bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
  	gatt_db_service_add_descriptor(service, &uuid,
  				BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
  				gatt_svc_chngd_ccc_read_cb,
  				gatt_svc_chngd_ccc_write_cb, server);
  
  	gatt_db_service_set_active(service, true);
  }
  
  static void populate_db(struct server *server)
  {
  	populate_gap_service(server);
  	populate_gatt_service(server);
  }
  
  static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
  {
  	struct server *server;
  	size_t name_len = strlen(test_device_name);
  
  	server = new0(struct server, 1);
  	if (!server) {
  		fprintf(stderr, "Failed to allocate memory for server\n");
  		return NULL;
  	}
  
  	server->att = bt_att_new(fd, false);
  	if (!server->att) {
  		fprintf(stderr, "Failed to initialze ATT transport layer\n");
  		goto fail;
  	}
  
  	if (!bt_att_set_close_on_unref(server->att, true)) {
  		fprintf(stderr, "Failed to set up ATT transport layer\n");
  		goto fail;
  	}
  
  	if (!bt_att_register_disconnect(server->att, att_disconnect_cb, NULL,
  									NULL)) {
  		fprintf(stderr, "Failed to set ATT disconnect handler\n");
  		goto fail;
  	}
  
  	server->name_len = name_len + 1;
  	server->device_name = malloc(name_len + 1);
  	if (!server->device_name) {
  		fprintf(stderr, "Failed to allocate memory for device name\n");
  		goto fail;
  	}
  
  	memcpy(server->device_name, test_device_name, name_len);
  	server->device_name[name_len] = '\0';
  
  	server->fd = fd;
  	server->db = gatt_db_new();
  	if (!server->db) {
  		fprintf(stderr, "Failed to create GATT database\n");
  		goto fail;
  	}
  
  	server->gatt = bt_gatt_server_new(server->db, server->att, mtu);
  	if (!server->gatt) {
  		fprintf(stderr, "Failed to create GATT server\n");
  		goto fail;
  	}
  
  	if (verbose) {
  		bt_att_set_debug(server->att, att_debug_cb, "att: ", NULL);
  		bt_gatt_server_set_debug(server->gatt, gatt_debug_cb,
  							"server: ", NULL);
  	}
  	/* bt_gatt_server already holds a reference */
  	populate_db(server);
  
  	return server;
  
  fail:
  	gatt_db_unref(server->db);
  	free(server->device_name);
  	bt_att_unref(server->att);
  	free(server);
  
  	return NULL;
  }
  
  static void server_destroy(struct server *server)
  {
  	bt_gatt_server_unref(server->gatt);
  	gatt_db_unref(server->db);
  }
  
  static void usage(void)
  {
  	printf("btgatt-server\n");
  	printf("Usage:\n\tbtgatt-server [options]\n");
  
  	printf("Options:\n"
  		"\t-i, --index <id>\t\tSpecify adapter index, e.g. hci0\n"
  		"\t-v, --verbose\t\t\tEnable extra logging\n"
  		"\t-h, --help\t\t\tDisplay help\n");
  }
  
  static struct option main_options[] = {
  	{ "index",		1, 0, 'i' },
  	{ "verbose",		0, 0, 'v' },
  	{ "help",		0, 0, 'h' },
  	{ }
  };
  
  static int l2cap_le_att_listen_and_accept(bdaddr_t *src, int sec,
  							uint8_t src_type)
  {
  	int sk, nsk;
  	struct sockaddr_l2 srcaddr, addr;
  	socklen_t optlen;
  	struct bt_security btsec;
  	char ba[18];
  
  	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
  	if (sk < 0) {
  		perror("Failed to create L2CAP socket");
  		return -1;
  	}
  
  	/* Set up source address */
  	memset(&srcaddr, 0, sizeof(srcaddr));
  	srcaddr.l2_family = AF_BLUETOOTH;
  	srcaddr.l2_cid = htobs(ATT_CID);
  	srcaddr.l2_bdaddr_type = src_type;
  	bacpy(&srcaddr.l2_bdaddr, src);
  
  	if (bind(sk, (struct sockaddr *) &srcaddr, sizeof(srcaddr)) < 0) {
  		perror("Failed to bind L2CAP socket");
  		goto fail;
  	}
  
  	/* Set the security level */
  	memset(&btsec, 0, sizeof(btsec));
  	btsec.level = sec;
  	if (setsockopt(sk, SOL_BLUETOOTH, BT_SECURITY, &btsec,
  							sizeof(btsec)) != 0) {
  		fprintf(stderr, "Failed to set L2CAP security level\n");
  		goto fail;
  	}
  
  	if (listen(sk, 10) < 0) {
  		perror("Listening on socket failed");
  		goto fail;
  	}
  
  	printf("Started listening on ATT channel. Waiting for connections\n");
  
  	memset(&addr, 0, sizeof(addr));
  	optlen = sizeof(addr);
  	nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
  	if (nsk < 0) {
  		perror("Accept failed");
  		goto fail;
  	}
  
  	ba2str(&addr.l2_bdaddr, ba);
  	printf("Connect from %s\n", ba);
  	close(sk);
  
  	return nsk;
  
  fail:
  	close(sk);
  	return -1;
  }
  
  static void signal_cb(int signum, void *user_data)
  {
  	switch (signum) {
  	case SIGINT:
  	case SIGTERM:
  		mainloop_quit();
  		break;
  	default:
  		break;
  	}
  }
  
  int main(int argc, char *argv[])
  {
  	int opt;
  	bdaddr_t src_addr;
  	int dev_id = -1;
  	int fd;
  	int sec = BT_SECURITY_LOW;
  	uint8_t src_type = BDADDR_LE_PUBLIC;
  	uint16_t mtu = 0;
  	sigset_t mask;
  	bool hr_visible = false;
  	struct server *server;
  
  	while ((opt = getopt_long(argc, argv, "+hvrs:t:m:i:",
  						main_options, NULL)) != -1) {
  		switch (opt) {
  		case 'h':
  			usage();
  			return EXIT_SUCCESS;
  		case 'v':
  			verbose = true;
  			break;
  		case 'i':
  			dev_id = hci_devid(optarg);
  			if (dev_id < 0) {
  				perror("Invalid adapter");
  				return EXIT_FAILURE;
  			}
  
  			break;
  		default:
  			fprintf(stderr, "Invalid option: %c\n", opt);
  			return EXIT_FAILURE;
  		}
  	}
  
  	argc -= optind;
  	argv -= optind;
  	optind = 0;
  
  	if (argc) {
  		usage();
  		return EXIT_SUCCESS;
  	}
  
  	if (dev_id == -1)
  		bacpy(&src_addr, BDADDR_ANY);
  	else if (hci_devba(dev_id, &src_addr) < 0) {
  		perror("Adapter not available");
  		return EXIT_FAILURE;
  	}
          advertise();
  	fd = l2cap_le_att_listen_and_accept(&src_addr, sec, src_type);
  	if (fd < 0) {
  		fprintf(stderr, "Failed to accept L2CAP ATT connection\n");
  		return EXIT_FAILURE;
  	}
  
  	mainloop_init();
  
  	server = server_create(fd, mtu, hr_visible);
  	if (!server) {
  		close(fd);
  		return EXIT_FAILURE;
  	}
  	printf("Running GATT server\n");
  
  	sigemptyset(&mask);
  	sigaddset(&mask, SIGINT);
  	sigaddset(&mask, SIGTERM);
  
  	mainloop_set_signal(&mask, signal_cb, NULL, NULL);
  
  	print_prompt();
  
  	mainloop_run();
  
  	printf("\n\nShutting down...\n");
  
  	server_destroy(server);
  
  	return EXIT_SUCCESS;
  }
  