int gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id)
{
	if (im == NULL || id < 0 || id > GD_METHOD_COUNT) {
		return 0;
	}

	switch (id) {
		case GD_DEFAULT:
			id = GD_BILINEAR_FIXED;
		/* Optimized versions */
		case GD_BILINEAR_FIXED:
		case GD_BICUBIC_FIXED:
		case GD_NEAREST_NEIGHBOUR:
		case GD_WEIGHTED4:
			im->interpolation = NULL;
			break;

		/* generic versions*/
		case GD_BELL:
			im->interpolation = filter_bell;
			break;
		case GD_BESSEL:
			im->interpolation = filter_bessel;
			break;
		case GD_BICUBIC:
			im->interpolation = filter_bicubic;
			break;
		case GD_BLACKMAN:
			im->interpolation = filter_blackman;
			break;
		case GD_BOX:
			im->interpolation = filter_box;
			break;
		case GD_BSPLINE:
			im->interpolation = filter_bspline;
			break;
		case GD_CATMULLROM:
			im->interpolation = filter_catmullrom;
			break;
		case GD_GAUSSIAN:
			im->interpolation = filter_gaussian;
			break;
		case GD_GENERALIZED_CUBIC:
			im->interpolation = filter_generalized_cubic;
			break;
		case GD_HERMITE:
			im->interpolation = filter_hermite;
			break;
		case GD_HAMMING:
			im->interpolation = filter_hamming;
			break;
		case GD_HANNING:
			im->interpolation = filter_hanning;
			break;
		case GD_MITCHELL:
			im->interpolation = filter_mitchell;
			break;
		case GD_POWER:
			im->interpolation = filter_power;
			break;
		case GD_QUADRATIC:
			im->interpolation = filter_quadratic;
			break;
		case GD_SINC:
			im->interpolation = filter_sinc;
			break;
		case GD_TRIANGLE:
			im->interpolation = filter_triangle;
			break;

		default:
			return 0;
			break;
	}
	im->interpolation_id = id;
	return 1;
}


 */
static void php_wddx_push_element(void *user_data, const XML_Char *name, const XML_Char **atts)
{
	st_entry ent;
	wddx_stack *stack = (wddx_stack *)user_data;
	if (!strcmp((char *)name, EL_PACKET)) {
		int i;

		if (atts) for (i=0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_VERSION)) {
				/* nothing for now */
			}
		}
	} else if (!strcmp((char *)name, EL_STRING)) {
		ent.type = ST_STRING;
		SET_STACK_VARNAME;

		ZVAL_STR(&ent.data, ZSTR_EMPTY_ALLOC());
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_BINARY)) {
		ent.type = ST_BINARY;
		SET_STACK_VARNAME;

		ZVAL_STR(&ent.data, ZSTR_EMPTY_ALLOC());
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_CHAR)) {
		int i;

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_CHAR_CODE) && atts[++i] && atts[i][0]) {
				char tmp_buf[2];

				snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol((char *)atts[i], NULL, 16));
				php_wddx_process_data(user_data, (XML_Char *) tmp_buf, strlen(tmp_buf));
				break;
			}
		}
	} else if (!strcmp((char *)name, EL_NUMBER)) {
		ent.type = ST_NUMBER;
		SET_STACK_VARNAME;

		ZVAL_LONG(&ent.data, 0);
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_BOOLEAN)) {
		int i;

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_VALUE) && atts[++i] && atts[i][0]) {
				ent.type = ST_BOOLEAN;
				SET_STACK_VARNAME;

				ZVAL_TRUE(&ent.data);
				wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
				php_wddx_process_data(user_data, atts[i], strlen((char *)atts[i]));
				break;
			}
		}
	} else if (!strcmp((char *)name, EL_NULL)) {
		ent.type = ST_NULL;
		SET_STACK_VARNAME;

		ZVAL_NULL(&ent.data);

		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_ARRAY)) {
		ent.type = ST_ARRAY;
		SET_STACK_VARNAME;

		array_init(&ent.data);
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_STRUCT)) {
		ent.type = ST_STRUCT;
		SET_STACK_VARNAME;
		array_init(&ent.data);
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_VAR)) {
		int i;

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
				stack->varname = estrdup((char *)atts[i]);
				break;
			}
		}
	} else if (!strcmp((char *)name, EL_RECORDSET)) {
		int i;

		ent.type = ST_RECORDSET;
		SET_STACK_VARNAME;
		array_init(&ent.data);

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], "fieldNames") && atts[++i] && atts[i][0]) {
				zval tmp;
				char *key;
				const char *p1, *p2, *endp;

				endp = (char *)atts[i] + strlen((char *)atts[i]);
				p1 = (char *)atts[i];
				while ((p2 = php_memnstr(p1, ",", sizeof(",")-1, endp)) != NULL) {
					key = estrndup(p1, p2 - p1);
					array_init(&tmp);
					add_assoc_zval_ex(&ent.data, key, p2 - p1, &tmp);
					p1 = p2 + sizeof(",")-1;
					efree(key);
				}

				if (p1 <= endp) {
					array_init(&tmp);
					add_assoc_zval_ex(&ent.data, p1, endp - p1, &tmp);
				}

				break;
			}
		}

		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_FIELD)) {
		int i;
		st_entry ent;

		ent.type = ST_FIELD;
		ent.varname = NULL;
		ZVAL_UNDEF(&ent.data);

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
				st_entry *recordset;
				zval *field;

				if (wddx_stack_top(stack, (void**)&recordset) == SUCCESS &&
					recordset->type == ST_RECORDSET &&
					(field = zend_hash_str_find(Z_ARRVAL(recordset->data), (char*)atts[i], strlen((char *)atts[i]))) != NULL) {
					ZVAL_COPY_VALUE(&ent.data, field);
				}

				break;
			}
		}

		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_DATETIME)) {
		ent.type = ST_DATETIME;
		SET_STACK_VARNAME;

		ZVAL_LONG(&ent.data, 0);
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	}


 */
static int wddx_stack_top(wddx_stack *stack, void **element)
{
	if (stack->top > 0) {
		*element = stack->elements[stack->top - 1];
		return SUCCESS;
	} else {
		*element = NULL;
		return FAILURE;
	}


   Starts a WDDX packet with optional comment and returns the packet id */
PHP_FUNCTION(wddx_packet_start)
{
	char *comment = NULL;
	size_t comment_len = 0;
	wddx_packet *packet;

	comment = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &comment, &comment_len) == FAILURE) {
		return;
	}

	packet = php_wddx_constructor();

	php_wddx_packet_start(packet, comment, comment_len);
	php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);

	RETURN_RES(zend_register_resource(packet, le_wddx));


 */
static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
{
	zval *ent;
	zend_string *key;
	int is_struct = 0;
	zend_ulong idx;
	HashTable *target_hash;
	char tmp_buf[WDDX_BUF_LEN];
	zend_ulong ind = 0;

	target_hash = Z_ARRVAL_P(arr);
	ZEND_HASH_FOREACH_KEY(target_hash, idx, key) {
		if (key) {
			is_struct = 1;
			break;
		}

		if (idx != ind) {
			is_struct = 1;
			break;
		}
		ind++;
	} ZEND_HASH_FOREACH_END();

	if (is_struct) {
		php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
	} else {
		snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
		php_wddx_add_chunk(packet, tmp_buf);
	}

	ZEND_HASH_FOREACH_KEY_VAL(target_hash, idx, key, ent) {
		if (ent == arr) {
			continue;
		}

		if (is_struct) {
			if (key) {
				php_wddx_serialize_var(packet, ent, key);
			} else {
				key = zend_long_to_str(idx);
				php_wddx_serialize_var(packet, ent, key);
				zend_string_release(key);
			}
		} else {
			php_wddx_serialize_var(packet, ent, NULL);
		}
	} ZEND_HASH_FOREACH_END();

	if (is_struct) {
		php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
	} else {
		php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
	}


 */
static int wddx_stack_destroy(wddx_stack *stack)
{
	register int i;

	if (stack->elements) {
		for (i = 0; i < stack->top; i++) {
			zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
			if (((st_entry *)stack->elements[i])->varname) {
				efree(((st_entry *)stack->elements[i])->varname);
			}
			efree(stack->elements[i]);
		}
		efree(stack->elements);
	}
	return SUCCESS;


   Serializes given variables and adds them to packet given by packet_id */
PHP_FUNCTION(wddx_add_vars)
{
	int num_args, i;
	zval *args = NULL;
	zval *packet_id;
	wddx_packet *packet = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r+", &packet_id, &args, &num_args) == FAILURE) {
		return;
	}

	if ((packet = (wddx_packet *)zend_fetch_resource(Z_RES_P(packet_id), "WDDX packet ID", le_wddx)) == NULL) {
		RETURN_FALSE;
	}

	for (i=0; i<num_args; i++) {
		zval *arg;
		if (!Z_ISREF(args[i])) {
			arg = &args[i];
		} else {
			arg = Z_REFVAL(args[i]);
		}
		if (Z_TYPE_P(arg) != IS_ARRAY && Z_TYPE_P(arg) != IS_OBJECT) {
			convert_to_string_ex(arg);
		}
		php_wddx_add_var(packet, arg);
	}

	RETURN_TRUE;


 */
static int wddx_stack_is_empty(wddx_stack *stack)
{
	if (stack->top == 0) {
		return 1;
	} else {
		return 0;
	}


static void release_wddx_packet_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
	smart_str *str = (smart_str *)rsrc->ptr;
	smart_str_free(str);
	efree(str);
}


static int add_string(zval* list, char* id, char* string) {
	if(id) return add_assoc_string(list, id, string);
	else   return add_next_index_string(list, string);
}


PHP_FUNCTION(xmlrpc_server_register_method)
{
	char *method_key;
	size_t method_key_len;
	zval *handle, *method_name;
	xmlrpc_server_data* server;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz", &handle, &method_key, &method_key_len, &method_name) == FAILURE) {
		return;
	}

	if ((server = (xmlrpc_server_data *)zend_fetch_resource(Z_RES_P(handle), "xmlrpc server", le_xmlrpc_server)) == NULL) {
		RETURN_FALSE;
	}

	/* register with C engine. every method just calls our standard callback,
	 * and it then dispatches to php as necessary
	 */
	if (XMLRPC_ServerRegisterMethod(server->server_ptr, method_key, php_xmlrpc_callback)) {
		/* save for later use */

		if (Z_REFCOUNTED_P(method_name)) {
			Z_ADDREF_P(method_name);
		}
		/* register our php method */
		add_zval(&server->method_map, method_key, method_name);

		RETURN_TRUE;
	}
}


static XMLRPC_VALUE php_xmlrpc_callback(XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* data) /* {{{ */
{
	xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
	zval* php_function;
	zval xmlrpc_params;
	zval callback_params[3];

	zval_ptr_dtor(&pData->xmlrpc_method);
	zval_ptr_dtor(&pData->return_data);

	/* convert xmlrpc to native php types */
	ZVAL_STRING(&pData->xmlrpc_method, XMLRPC_RequestGetMethodName(xRequest));
	XMLRPC_to_PHP(XMLRPC_RequestGetData(xRequest), &xmlrpc_params);

	/* check if the called method has been previous registered */
	if ((php_function = zend_hash_find(Z_ARRVAL(pData->server->method_map), Z_STR(pData->xmlrpc_method))) != NULL) {
		ZVAL_COPY_VALUE(&pData->php_function, php_function);
	}

	/* setup data hoojum */
	ZVAL_COPY_VALUE(&callback_params[0], &pData->xmlrpc_method);
	ZVAL_COPY_VALUE(&callback_params[1], &xmlrpc_params);
	ZVAL_COPY_VALUE(&callback_params[2], &pData->caller_params);

	/* Use same C function for all methods */

	/* php func prototype: function user_func($method_name, $xmlrpc_params, $user_params) */
	call_user_function(CG(function_table), NULL, &pData->php_function, &pData->return_data, 3, callback_params);

	pData->php_executed = 1;

	zval_ptr_dtor(&xmlrpc_params);

	return PHP_to_XMLRPC(&pData->return_data);
}


static int add_long(zval* list, char* id, int num) {
	if(id) return add_assoc_long(list, id, num);
	else   return add_next_index_long(list, num);
}


static long unix_stream_data_wait(struct sock *sk, long timeo,
				  struct sk_buff *last, unsigned int last_len)
{
	struct sk_buff *tail;
	DEFINE_WAIT(wait);

	unix_state_lock(sk);

	for (;;) {
		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);

		tail = skb_peek_tail(&sk->sk_receive_queue);
		if (tail != last ||
		    (tail && tail->len != last_len) ||
		    sk->sk_err ||
		    (sk->sk_shutdown & RCV_SHUTDOWN) ||
		    signal_pending(current) ||
		    !timeo)
			break;

		sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
		unix_state_unlock(sk);
		timeo = freezable_schedule_timeout(timeo);
		unix_state_lock(sk);

		if (sock_flag(sk, SOCK_DEAD))
			break;

		sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
	}

	finish_wait(sk_sleep(sk), &wait);
	unix_state_unlock(sk);
	return timeo;
}


static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
			  struct sk_buff_head *hitlist)
{
	struct sk_buff *skb;
	struct sk_buff *next;

	spin_lock(&x->sk_receive_queue.lock);
	skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
		/* Do we have file descriptors ? */
		if (UNIXCB(skb).fp) {
			bool hit = false;
			/* Process the descriptors of this socket */
			int nfd = UNIXCB(skb).fp->count;
			struct file **fp = UNIXCB(skb).fp->fp;

			while (nfd--) {
				/* Get the socket the fd matches if it indeed does so */
				struct sock *sk = unix_get_socket(*fp++);

				if (sk) {
					struct unix_sock *u = unix_sk(sk);

					/* Ignore non-candidates, they could
					 * have been added to the queues after
					 * starting the garbage collection
					 */
					if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) {
						hit = true;

						func(u);
					}
				}
			}
			if (hit && hitlist != NULL) {
				__skb_unlink(skb, &x->sk_receive_queue);
				__skb_queue_tail(hitlist, skb);
			}
		}
	}
	spin_unlock(&x->sk_receive_queue.lock);
}


PHP_FUNCTION(system)
{
	php_exec_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}


static char *guess_defbranch(void)
{
	const char *ref;
	unsigned char sha1[20];

	ref = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
	if (!ref || !starts_with(ref, "refs/heads/"))
		return "master";
	return xstrdup(ref + 11);
}


static char *build_snapshot_setting(int bitmap)
{
	const struct cgit_snapshot_format *f;
	struct strbuf result = STRBUF_INIT;

	for (f = cgit_snapshot_formats; f->suffix; f++) {
		if (f->bit & bitmap) {
			if (result.len)
				strbuf_addch(&result, ' ');
			strbuf_addstr(&result, f->suffix);
		}
	}
	return strbuf_detach(&result, NULL);
}


static void prepare_context(void)
{
	memset(&ctx, 0, sizeof(ctx));
	ctx.cfg.agefile = "info/web/last-modified";
	ctx.cfg.nocache = 0;
	ctx.cfg.cache_size = 0;
	ctx.cfg.cache_max_create_time = 5;
	ctx.cfg.cache_root = CGIT_CACHE_ROOT;
	ctx.cfg.cache_about_ttl = 15;
	ctx.cfg.cache_snapshot_ttl = 5;
	ctx.cfg.cache_repo_ttl = 5;
	ctx.cfg.cache_root_ttl = 5;
	ctx.cfg.cache_scanrc_ttl = 15;
	ctx.cfg.cache_dynamic_ttl = 5;
	ctx.cfg.cache_static_ttl = -1;
	ctx.cfg.case_sensitive_sort = 1;
	ctx.cfg.branch_sort = 0;
	ctx.cfg.commit_sort = 0;
	ctx.cfg.css = "/cgit.css";
	ctx.cfg.logo = "/cgit.png";
	ctx.cfg.favicon = "/favicon.ico";
	ctx.cfg.local_time = 0;
	ctx.cfg.enable_http_clone = 1;
	ctx.cfg.enable_index_owner = 1;
	ctx.cfg.enable_tree_linenumbers = 1;
	ctx.cfg.enable_git_config = 0;
	ctx.cfg.max_repo_count = 50;
	ctx.cfg.max_commit_count = 50;
	ctx.cfg.max_lock_attempts = 5;
	ctx.cfg.max_msg_len = 80;
	ctx.cfg.max_repodesc_len = 80;
	ctx.cfg.max_blob_size = 0;
	ctx.cfg.max_stats = 0;
	ctx.cfg.project_list = NULL;
	ctx.cfg.renamelimit = -1;
	ctx.cfg.remove_suffix = 0;
	ctx.cfg.robots = "index, nofollow";
	ctx.cfg.root_title = "Git repository browser";
	ctx.cfg.root_desc = "a fast webinterface for the git dscm";
	ctx.cfg.scan_hidden_path = 0;
	ctx.cfg.script_name = CGIT_SCRIPT_NAME;
	ctx.cfg.section = "";
	ctx.cfg.repository_sort = "name";
	ctx.cfg.section_sort = 1;
	ctx.cfg.summary_branches = 10;
	ctx.cfg.summary_log = 10;
	ctx.cfg.summary_tags = 10;
	ctx.cfg.max_atom_items = 10;
	ctx.cfg.difftype = DIFF_UNIFIED;
	ctx.env.cgit_config = getenv("CGIT_CONFIG");
	ctx.env.http_host = getenv("HTTP_HOST");
	ctx.env.https = getenv("HTTPS");
	ctx.env.no_http = getenv("NO_HTTP");
	ctx.env.path_info = getenv("PATH_INFO");
	ctx.env.query_string = getenv("QUERY_STRING");
	ctx.env.request_method = getenv("REQUEST_METHOD");
	ctx.env.script_name = getenv("SCRIPT_NAME");
	ctx.env.server_name = getenv("SERVER_NAME");
	ctx.env.server_port = getenv("SERVER_PORT");
	ctx.env.http_cookie = getenv("HTTP_COOKIE");
	ctx.env.http_referer = getenv("HTTP_REFERER");
	ctx.env.content_length = getenv("CONTENT_LENGTH") ? strtoul(getenv("CONTENT_LENGTH"), NULL, 10) : 0;
	ctx.env.authenticated = 0;
	ctx.page.mimetype = "text/html";
	ctx.page.charset = PAGE_ENCODING;
	ctx.page.filename = NULL;
	ctx.page.size = 0;
	ctx.page.modified = time(NULL);
	ctx.page.expires = ctx.page.modified;
	ctx.page.etag = NULL;
	memset(&ctx.cfg.mimetypes, 0, sizeof(struct string_list));
	if (ctx.env.script_name)
		ctx.cfg.script_name = xstrdup(ctx.env.script_name);
	if (ctx.env.query_string)
		ctx.qry.raw = xstrdup(ctx.env.query_string);
	if (!ctx.env.cgit_config)
		ctx.env.cgit_config = CGIT_CONFIG;
}


static char *http_date(time_t t)
{
	static char day[][4] =
		{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
	static char month[][4] =
		{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
	struct tm *tm = gmtime(&t);
	return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday],
		   tm->tm_mday, month[tm->tm_mon], 1900 + tm->tm_year,
		   tm->tm_hour, tm->tm_min, tm->tm_sec);
}


void html_attrf(const char *fmt, ...)
{
	va_list ap;
	struct strbuf sb = STRBUF_INIT;

	va_start(ap, fmt);
	strbuf_vaddf(&sb, fmt, ap);
	va_end(ap);

	html_attr(sb.buf);
	strbuf_release(&sb);
}


void html_url_arg(const char *txt)
{
	const char *t = txt;
	while (t && *t) {
		unsigned char c = *t;
		const char *e = url_escape_table[c];
		if (c == ' ')
			e = "+";
		if (e) {
			html_raw(txt, t - txt);
			html(e);
			txt = t + 1;
		}
		t++;
	}
	if (t != txt)
		html(txt);
}


void cgit_redirect(const char *url, bool permanent)
{
	htmlf("Status: %d %s\n", permanent ? 301 : 302, permanent ? "Moved" : "Found");
	html("Location: ");
	html_url_path(url);
	html("\n\n");
	exit(0);
}


void cgit_print_error(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	cgit_vprint_error(fmt, ap);
	va_end(ap);
}


void cgit_print_http_headers(void)
{
	if (ctx.env.no_http && !strcmp(ctx.env.no_http, "1"))
		return;

	if (ctx.page.status)
		htmlf("Status: %d %s\n", ctx.page.status, ctx.page.statusmsg);
	if (ctx.page.mimetype && ctx.page.charset)
		htmlf("Content-Type: %s; charset=%s\n", ctx.page.mimetype,
		      ctx.page.charset);
	else if (ctx.page.mimetype)
		htmlf("Content-Type: %s\n", ctx.page.mimetype);
	if (ctx.page.size)
		htmlf("Content-Length: %zd\n", ctx.page.size);
	if (ctx.page.filename) {
		html("Content-Disposition: inline; filename=\"");
		html_header_arg_in_quotes(ctx.page.filename);
		html("\"\n");
	}
	if (!ctx.env.authenticated)
		html("Cache-Control: no-cache, no-store\n");
	htmlf("Last-Modified: %s\n", http_date(ctx.page.modified));
	htmlf("Expires: %s\n", http_date(ctx.page.expires));
	if (ctx.page.etag)
		htmlf("ETag: \"%s\"\n", ctx.page.etag);
	html("\n");
	if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
		exit(0);
}


int html_include(const char *filename)
{
	FILE *f;
	char buf[4096];
	size_t len;

	if (!(f = fopen(filename, "r"))) {
		fprintf(stderr, "[cgit] Failed to include file %s: %s (%d).\n",
			filename, strerror(errno), errno);
		return -1;
	}
	while ((len = fread(buf, 1, 4096, f)) > 0)
		html_raw(buf, len);
	fclose(f);
	return 0;
}


const char *cgit_loginurl(void)
{
	static const char *login_url;
	if (!login_url)
		login_url = fmtalloc("%s?p=login", cgit_rooturl());
	return login_url;
}


_setimage(ImagingEncoderObject* encoder, PyObject* args)
{
    PyObject* op;
    Imaging im;
    ImagingCodecState state;
    int x0, y0, x1, y1;

    /* Define where image data should be stored */

    x0 = y0 = x1 = y1 = 0;

    /* FIXME: should publish the ImagingType descriptor */
    if (!PyArg_ParseTuple(args, "O|(iiii)", &op, &x0, &y0, &x1, &y1))
	return NULL;
    im = PyImaging_AsImaging(op);
    if (!im)
	return NULL;

    encoder->im = im;

    state = &encoder->state;

    if (x0 == 0 && x1 == 0) {
	state->xsize = im->xsize;
	state->ysize = im->ysize;
    } else {
	state->xoff = x0;
	state->yoff = y0;
	state->xsize = x1 - x0;
	state->ysize = y1 - y0;
    }

    if (state->xsize <= 0 ||
	state->xsize + state->xoff > im->xsize ||
	state->ysize <= 0 ||
	state->ysize + state->yoff > im->ysize) {
	PyErr_SetString(PyExc_SystemError, "tile cannot extend outside image");
	return NULL;
    }

    /* Allocate memory buffer (if bits field is set) */
    if (state->bits > 0) {
	state->bytes = (state->bits * state->xsize+7)/8;
	state->buffer = (UINT8*) malloc(state->bytes);
	if (!state->buffer)
	    return PyErr_NoMemory();
    }

    /* Keep a reference to the image object, to make sure it doesn't
       go away before we do */
    Py_INCREF(op);
    Py_XDECREF(encoder->lock);
    encoder->lock = op;

    Py_INCREF(Py_None);
    return Py_None;
}


PyImaging_SunRleDecoderNew(PyObject* self, PyObject* args)
{
    ImagingDecoderObject* decoder;

    char* mode;
    char* rawmode;
    if (!PyArg_ParseTuple(args, "ss", &mode, &rawmode))
        return NULL;

    decoder = PyImaging_DecoderNew(0);
    if (decoder == NULL)
        return NULL;

    if (get_unpacker(decoder, mode, rawmode) < 0)
        return NULL;

    decoder->decode = ImagingSunRleDecode;

    return (PyObject*) decoder;
}


do_trustkey(
	sockaddr_u *srcadr,
	endpt *inter,
	struct req_pkt *inpkt,
	u_long trust
	)
{
	register uint32_t *kp;
	register int items;

	items = INFO_NITEMS(inpkt->err_nitems);
	kp = (uint32_t *)&inpkt->u;
	while (items-- > 0) {
		authtrust(*kp, trust);
		kp++;
	}

	req_ack(srcadr, inter, inpkt, INFO_OKAY);
}


pushRestriction(
	RestrictStackT  **spp,
	const restrict_u *ptr
	)
{
	RestrictStackT *sp;

	if (NULL == (sp = *spp) || 0 == sp->fcnt) {
		/* need another sheet in the scratch pad */
		sp = emalloc(sizeof(*sp));
		sp->link = *spp;
		sp->fcnt = getStackSheetSize(sp);
		*spp = sp;
	}
	sp->pres[--sp->fcnt] = ptr;
	return TRUE;
}


list_restrict(
	sockaddr_u *srcadr,
	endpt *inter,
	struct req_pkt *inpkt
	)
{
	struct info_restrict *ir;

	DPRINTF(3, ("wants restrict list summary\n"));

	ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt,
	    v6sizeof(struct info_restrict));

	/*
	 * The restriction lists are kept sorted in the reverse order
	 * than they were originally.  To preserve the output semantics,
	 * dump each list in reverse order. The workers take care of that.
	 */
	list_restrict4(restrictlist4, &ir);
	if (client_v6_capable)
		list_restrict6(restrictlist6, &ir);
	flush_pkt();
}


free_config_phone(
	config_tree *ptree
	)
{
	FREE_STRING_FIFO(ptree->phone);
}


get_logmask(
	const char *	str
	)
{
	const char *	t;
	u_int32		offset;
	u_int32		mask;

	mask = get_match(str, logcfg_noclass_items);
	if (mask != 0)
		return mask;

	t = str;
	offset = get_pfxmatch(&t, logcfg_class);
	mask   = get_match(t, logcfg_class_items);

	if (mask)
		return mask << offset;
	else
		msyslog(LOG_ERR, "logconfig: '%s' not recognized - ignored",
			str);

	return 0;
}


config_trap(
	config_tree *ptree
	)
{
	addr_opts_node *curr_trap;
	attr_val *curr_opt;
	sockaddr_u addr_sock;
	sockaddr_u peeraddr;
	struct interface *localaddr;
	struct addrinfo hints;
	char port_text[8];
	settrap_parms *pstp;
	u_short port;
	int err_flag;
	int rc;

	/* silence warning about addr_sock potentially uninitialized */
	AF(&addr_sock) = AF_UNSPEC;

	curr_trap = HEAD_PFIFO(ptree->trap);
	for (; curr_trap != NULL; curr_trap = curr_trap->link) {
		err_flag = 0;
		port = 0;
		localaddr = NULL;

		curr_opt = HEAD_PFIFO(curr_trap->options);
		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
			if (T_Port == curr_opt->attr) {
				if (curr_opt->value.i < 1
				    || curr_opt->value.i > USHRT_MAX) {
					msyslog(LOG_ERR,
						"invalid port number "
						"%d, trap ignored",
						curr_opt->value.i);
					err_flag = 1;
				}
				port = (u_short)curr_opt->value.i;
			}
			else if (T_Interface == curr_opt->attr) {
				/* Resolve the interface address */
				ZERO_SOCK(&addr_sock);
				if (getnetnum(curr_opt->value.s,
					      &addr_sock, 1, t_UNK) != 1) {
					err_flag = 1;
					break;
				}

				localaddr = findinterface(&addr_sock);

				if (NULL == localaddr) {
					msyslog(LOG_ERR,
						"can't find interface with address %s",
						stoa(&addr_sock));
					err_flag = 1;
				}
			}
		}

		/* Now process the trap for the specified interface
		 * and port number
		 */
		if (!err_flag) {
			if (!port)
				port = TRAPPORT;
			ZERO_SOCK(&peeraddr);
			rc = getnetnum(curr_trap->addr->address,
				       &peeraddr, 1, t_UNK);
			if (1 != rc) {
#ifndef WORKER
				msyslog(LOG_ERR,
					"trap: unable to use IP address %s.",
					curr_trap->addr->address);
#else	/* WORKER follows */
				/*
				 * save context and hand it off
				 * for name resolution.
				 */
				ZERO(hints);
				hints.ai_protocol = IPPROTO_UDP;
				hints.ai_socktype = SOCK_DGRAM;
				snprintf(port_text, sizeof(port_text),
					 "%u", port);
				hints.ai_flags = Z_AI_NUMERICSERV;
				pstp = emalloc_zero(sizeof(*pstp));
				if (localaddr != NULL) {
					hints.ai_family = localaddr->family;
					pstp->ifaddr_nonnull = 1;
					memcpy(&pstp->ifaddr,
					       &localaddr->sin,
					       sizeof(pstp->ifaddr));
				}
				rc = getaddrinfo_sometime(
					curr_trap->addr->address,
					port_text, &hints,
					INITIAL_DNS_RETRY,
					&trap_name_resolved,
					pstp);
				if (!rc)
					msyslog(LOG_ERR,
						"config_trap: getaddrinfo_sometime(%s,%s): %m",
						curr_trap->addr->address,
						port_text);
#endif	/* WORKER */
				continue;
			}
			/* port is at same location for v4 and v6 */
			SET_PORT(&peeraddr, port);

			if (NULL == localaddr)
				localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
			else
				AF(&peeraddr) = AF(&addr_sock);

			if (!ctlsettrap(&peeraddr, localaddr, 0,
					NTP_VERSION))
				msyslog(LOG_ERR,
					"set trap %s -> %s failed.",
					latoa(localaddr),
					stoa(&peeraddr));
		}
	}
}


free_config_setvar(
	config_tree *ptree
	)
{
	FREE_SETVAR_FIFO(ptree->setvar);
}


config_peers(
	config_tree *ptree
	)
{
	sockaddr_u		peeraddr;
	struct addrinfo		hints;
	peer_node *		curr_peer;
	peer_resolved_ctx *	ctx;
	u_char			hmode;

	/* add servers named on the command line with iburst implied */
	for (;
	     cmdline_server_count > 0;
	     cmdline_server_count--, cmdline_servers++) {

		ZERO_SOCK(&peeraddr);
		/*
		 * If we have a numeric address, we can safely
		 * proceed in the mainline with it.  Otherwise, hand
		 * the hostname off to the blocking child.
		 */
		if (is_ip_address(*cmdline_servers, AF_UNSPEC,
				  &peeraddr)) {

			SET_PORT(&peeraddr, NTP_PORT);
			if (is_sane_resolved_address(&peeraddr,
						     T_Server))
				peer_config(
					&peeraddr,
					NULL,
					NULL,
					MODE_CLIENT,
					NTP_VERSION,
					0,
					0,
					FLAG_IBURST,
					0,
					0,
					NULL);
		} else {
			/* we have a hostname to resolve */
# ifdef WORKER
			ctx = emalloc_zero(sizeof(*ctx));
			ctx->family = AF_UNSPEC;
			ctx->host_mode = T_Server;
			ctx->hmode = MODE_CLIENT;
			ctx->version = NTP_VERSION;
			ctx->flags = FLAG_IBURST;

			ZERO(hints);
			hints.ai_family = (u_short)ctx->family;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;

			getaddrinfo_sometime(*cmdline_servers,
					     "ntp", &hints,
					     INITIAL_DNS_RETRY,
					     &peer_name_resolved,
					     (void *)ctx);
# else	/* !WORKER follows */
			msyslog(LOG_ERR,
				"hostname %s can not be used, please use IP address instead.",
				curr_peer->addr->address);
# endif
		}
	}

	/* add associations from the configuration file */
	curr_peer = HEAD_PFIFO(ptree->peers);
	for (; curr_peer != NULL; curr_peer = curr_peer->link) {
		ZERO_SOCK(&peeraddr);
		/* Find the correct host-mode */
		hmode = get_correct_host_mode(curr_peer->host_mode);
		INSIST(hmode != 0);

		if (T_Pool == curr_peer->host_mode) {
			AF(&peeraddr) = curr_peer->addr->type;
			peer_config(
				&peeraddr,
				curr_peer->addr->address,
				NULL,
				hmode,
				curr_peer->peerversion,
				curr_peer->minpoll,
				curr_peer->maxpoll,
				peerflag_bits(curr_peer),
				curr_peer->ttl,
				curr_peer->peerkey,
				curr_peer->group);
		/*
		 * If we have a numeric address, we can safely
		 * proceed in the mainline with it.  Otherwise, hand
		 * the hostname off to the blocking child.
		 */
		} else if (is_ip_address(curr_peer->addr->address,
				  curr_peer->addr->type, &peeraddr)) {

			SET_PORT(&peeraddr, NTP_PORT);
			if (is_sane_resolved_address(&peeraddr,
			    curr_peer->host_mode))
				peer_config(
					&peeraddr,
					NULL,
					NULL,
					hmode,
					curr_peer->peerversion,
					curr_peer->minpoll,
					curr_peer->maxpoll,
					peerflag_bits(curr_peer),
					curr_peer->ttl,
					curr_peer->peerkey,
					curr_peer->group);
		} else {
			/* we have a hostname to resolve */
# ifdef WORKER
			ctx = emalloc_zero(sizeof(*ctx));
			ctx->family = curr_peer->addr->type;
			ctx->host_mode = curr_peer->host_mode;
			ctx->hmode = hmode;
			ctx->version = curr_peer->peerversion;
			ctx->minpoll = curr_peer->minpoll;
			ctx->maxpoll = curr_peer->maxpoll;
			ctx->flags = peerflag_bits(curr_peer);
			ctx->ttl = curr_peer->ttl;
			ctx->keyid = curr_peer->peerkey;
			ctx->group = curr_peer->group;

			ZERO(hints);
			hints.ai_family = ctx->family;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;

			getaddrinfo_sometime(curr_peer->addr->address,
					     "ntp", &hints,
					     INITIAL_DNS_RETRY,
					     &peer_name_resolved, ctx);
# else	/* !WORKER follows */
			msyslog(LOG_ERR,
				"hostname %s can not be used, please use IP address instead.",
				curr_peer->addr->address);
# endif
		}
	}
}


YYID (yyi)
    int yyi;
#endif
{
  return yyi;
}


create_attr_ival(
	int attr,
	int value
	)
{
	attr_val *my_val;

	my_val = emalloc_zero(sizeof(*my_val));
	my_val->attr = attr;
	my_val->value.i = value;
	my_val->type = T_Integer;

	return my_val;
}


free_config_tos(
	config_tree *ptree
	)
{
	FREE_ATTR_VAL_FIFO(ptree->orphan_cmds);
}


yystpcpy (yydest, yysrc)
    char *yydest;
    const char *yysrc;
#endif
{
  char *yyd = yydest;
  const char *yys = yysrc;

  while ((*yyd++ = *yys++) != '\0')
    continue;

  return yyd - 1;
}


create_restrict_node(
	address_node *	addr,
	address_node *	mask,
	int_fifo *	flags,
	int		line_no
	)
{
	restrict_node *my_node;

	my_node = emalloc_zero(sizeof(*my_node));
	my_node->addr = addr;
	my_node->mask = mask;
	my_node->flags = flags;
	my_node->line_no = line_no;

	return my_node;
}


void cpu_physical_memory_unmap(void *buffer, hwaddr len,
                               int is_write, hwaddr access_len)
{
    return address_space_unmap(&address_space_memory, buffer, len, is_write, access_len);
}


static uint32_t phys_map_node_alloc(PhysPageMap *map)
{
    unsigned i;
    uint32_t ret;

    ret = map->nodes_nb++;
    assert(ret != PHYS_MAP_NODE_NIL);
    assert(ret != map->nodes_nb_alloc);
    for (i = 0; i < P_L2_SIZE; ++i) {
        map->nodes[ret][i].skip = 1;
        map->nodes[ret][i].ptr = PHYS_MAP_NODE_NIL;
    }
    return ret;
}


void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as)
{
    /* We only support one address space per cpu at the moment.  */
    assert(cpu->as == as);

    if (cpu->tcg_as_listener) {
        memory_listener_unregister(cpu->tcg_as_listener);
    } else {
        cpu->tcg_as_listener = g_new0(MemoryListener, 1);
    }
    cpu->tcg_as_listener->commit = tcg_commit;
    memory_listener_register(cpu->tcg_as_listener, as);
}


void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
{
    MapClient *client = g_malloc(sizeof(*client));

    client->opaque = opaque;
    client->callback = callback;
    QLIST_INSERT_HEAD(&map_client_list, client, link);
    return client;
}


static MemoryRegionSection *phys_page_find(PhysPageEntry lp, hwaddr addr,
                                           Node *nodes, MemoryRegionSection *sections)
{
    PhysPageEntry *p;
    hwaddr index = addr >> TARGET_PAGE_BITS;
    int i;

    for (i = P_L2_LEVELS; lp.skip && (i -= lp.skip) >= 0;) {
        if (lp.ptr == PHYS_MAP_NODE_NIL) {
            return &sections[PHYS_SECTION_UNASSIGNED];
        }
        p = nodes[lp.ptr];
        lp = p[(index >> (i * P_L2_BITS)) & (P_L2_SIZE - 1)];
    }

    if (sections[lp.ptr].size.hi ||
        range_covers_byte(sections[lp.ptr].offset_within_address_space,
                          sections[lp.ptr].size.lo, addr)) {
        return &sections[lp.ptr];
    } else {
        return &sections[PHYS_SECTION_UNASSIGNED];
    }
}


int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len,
                          int flags)
{
    return -ENOSYS;
}


void address_space_init_dispatch(AddressSpace *as)
{
    as->dispatch = NULL;
    as->dispatch_listener = (MemoryListener) {
        .begin = mem_begin,
        .commit = mem_commit,
        .region_add = mem_add,
        .region_nop = mem_add,
        .priority = 0,
    };
    memory_listener_register(&as->dispatch_listener, as);
}


void cpu_flush_icache_range(hwaddr start, int len)
{
    /*
     * This function should do the same thing as an icache flush that was
     * triggered from within the guest. For TCG we are always cache coherent,
     * so there is no need to flush anything. For KVM / Xen we need to flush
     * the host's instruction cache at least.
     */
    if (tcg_enabled()) {
        return;
    }

    cpu_physical_memory_write_rom_internal(&address_space_memory,
                                           start, NULL, len, FLUSH_CACHE);
}


ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp)
{
    return qemu_ram_alloc_internal(size, size, NULL, NULL, false, mr, errp);
}


static int memory_try_enable_merging(void *addr, size_t len)
{
    if (!machine_mem_merge(current_machine)) {
        /* disabled by the user */
        return 0;
    }

    return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
}


void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
{
    RAMBlock *new_block, *block;

    rcu_read_lock();
    new_block = find_ram_block(addr);
    assert(new_block);
    assert(!new_block->idstr[0]);

    if (dev) {
        char *id = qdev_get_dev_path(dev);
        if (id) {
            snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
            g_free(id);
        }
    }
    pstrcat(new_block->idstr, sizeof(new_block->idstr), name);

    QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
        if (block != new_block && !strcmp(block->idstr, new_block->idstr)) {
            fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
                    new_block->idstr);
            abort();
        }
    }
    rcu_read_unlock();
}


bool address_space_write(AddressSpace *as, hwaddr addr,
                         const uint8_t *buf, int len)
{
    return address_space_rw(as, addr, (uint8_t *)buf, len, true);
}


static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
                                                  MemTxAttrs attrs,
                                                  MemTxResult *result,
                                                  enum device_endian endian)
{
    uint8_t *ptr;
    uint64_t val;
    MemoryRegion *mr;
    hwaddr l = 4;
    hwaddr addr1;
    MemTxResult r;

    rcu_read_lock();
    mr = address_space_translate(as, addr, &addr1, &l, false);
    if (l < 4 || !memory_access_is_direct(mr, false)) {
        /* I/O case */
        r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs);
#if defined(TARGET_WORDS_BIGENDIAN)
        if (endian == DEVICE_LITTLE_ENDIAN) {
            val = bswap32(val);
        }
#else
        if (endian == DEVICE_BIG_ENDIAN) {
            val = bswap32(val);
        }
#endif
    } else {
        /* RAM case */
        ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr)
                                & TARGET_PAGE_MASK)
                               + addr1);
        switch (endian) {
        case DEVICE_LITTLE_ENDIAN:
            val = ldl_le_p(ptr);
            break;
        case DEVICE_BIG_ENDIAN:
            val = ldl_be_p(ptr);
            break;
        default:
            val = ldl_p(ptr);
            break;
        }
        r = MEMTX_OK;
    }
    if (result) {
        *result = r;
    }
    rcu_read_unlock();
    return val;
}


static uint32_t phys_map_node_alloc(PhysPageMap *map, bool leaf)
{
    unsigned i;
    uint32_t ret;
    PhysPageEntry e;
    PhysPageEntry *p;

    ret = map->nodes_nb++;
    p = map->nodes[ret];
    assert(ret != PHYS_MAP_NODE_NIL);
    assert(ret != map->nodes_nb_alloc);

    e.skip = leaf ? 0 : 1;
    e.ptr = leaf ? PHYS_SECTION_UNASSIGNED : PHYS_MAP_NODE_NIL;
    for (i = 0; i < P_L2_SIZE; ++i) {
        memcpy(&p[i], &e, sizeof(e));
    }
    return ret;
}


void address_space_stb(AddressSpace *as, hwaddr addr, uint32_t val,
                       MemTxAttrs attrs, MemTxResult *result)
{
    uint8_t v = val;
    MemTxResult r;

    r = address_space_rw(as, addr, attrs, &v, 1, 1);
    if (result) {
        *result = r;
    }
}


MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
                                const uint8_t *buf, int len)
{
    return address_space_rw(as, addr, attrs, (uint8_t *)buf, len, true);
}


void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val)
{
    address_space_stw_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
}


uint32_t address_space_ldl_le(AddressSpace *as, hwaddr addr,
                              MemTxAttrs attrs, MemTxResult *result)
{
    return address_space_ldl_internal(as, addr, attrs, result,
                                      DEVICE_LITTLE_ENDIAN);
}


void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr,
                 const Message& msg)
{
    buffer.allocate(RECORD_HEADER + rlHdr.length_);
    buffer << rlHdr << msg;
}


void buildServerHello(SSL& ssl, ServerHello& hello)
{
    if (ssl.getSecurity().get_resuming()) {
        memcpy(hello.random_,ssl.getSecurity().get_connection().server_random_,
               RAN_LEN);
        memcpy(hello.session_id_, ssl.getSecurity().get_resume().GetID(),
               ID_LEN);
    }
    else {
        ssl.getCrypto().get_random().Fill(hello.random_, RAN_LEN);
        ssl.getCrypto().get_random().Fill(hello.session_id_, ID_LEN);
    }
    hello.id_len_ = ID_LEN;
    ssl.set_sessionID(hello.session_id_);

    hello.cipher_suite_[0] = ssl.getSecurity().get_parms().suite_[0];
    hello.cipher_suite_[1] = ssl.getSecurity().get_parms().suite_[1];
    hello.compression_method_ = hello.compression_method_;

    hello.set_length(sizeof(ProtocolVersion) + RAN_LEN + ID_LEN +
                     sizeof(hello.id_len_) + SUITE_LEN + SIZEOF_ENUM);
}


input_buffer& operator>>(input_buffer& input, ChangeCipherSpec& cs)
{
    cs.type_ = CipherChoice(input[AUTO]);
    return input;
}


input_buffer& ServerHelloDone::set(input_buffer& in)
{
    return in;
}


void sendServerHello(SSL& ssl, BufferOutput buffer)
{
    if (ssl.getSecurity().get_resuming())
        ssl.verifyState(clientKeyExchangeComplete);
    else
        ssl.verifyState(clientHelloComplete);
    if (ssl.GetError()) return;

    ServerHello       sh(ssl.getSecurity().get_connection().version_,
                         ssl.getSecurity().get_connection().compression_);
    RecordLayerHeader rlHeader;
    HandShakeHeader   hsHeader;
    mySTL::auto_ptr<output_buffer> out(NEW_YS output_buffer);

    buildServerHello(ssl, sh);
    ssl.set_random(sh.get_random(), server_end);
    buildHeaders(ssl, hsHeader, rlHeader, sh);
    buildOutput(*out.get(), rlHeader, hsHeader, sh);
    hashHandShake(ssl, *out.get());

    if (buffer == buffered)
        ssl.addBuffer(out.release());
    else
        ssl.Send(out->get_buffer(), out->get_size());
}


void Data::set_length(uint16 l)
{
    length_ = l;
}


void ServerKeyExchange::build(SSL& ssl)
{
    server_key_->build(ssl);
    set_length(server_key_->get_length());
}


int ClientDiffieHellmanPublic::get_length() const
{
    return length_;
}


void SetErrorString(YasslError error, char* buffer)
{
    using namespace TaoCrypt;
    const int max = MAX_ERROR_SZ;  // shorthand
    int localError = error;        // errors from a few enums

    switch (localError) {

        // yaSSL proper errors
    case range_error :
        strncpy(buffer, "buffer index error, out of range", max);
        break;

    case realloc_error :
        strncpy(buffer, "trying to realloc a fixed buffer", max);
        break;

    case factory_error :
        strncpy(buffer, "unknown factory create request", max);
        break;

    case unknown_cipher :
        strncpy(buffer, "trying to use an unknown cipher", max);
        break;

    case prefix_error :
        strncpy(buffer, "bad master secret derivation, prefix too big", max);
        break;

    case record_layer :
        strncpy(buffer, "record layer not ready yet", max);
        break;

    case handshake_layer :
        strncpy(buffer, "handshake layer not ready yet", max);
        break;

    case out_of_order :
        strncpy(buffer, "handshake message received in wrong order", max);
        break;

    case bad_input :
        strncpy(buffer, "bad cipher suite input", max);
        break;

    case match_error :
        strncpy(buffer, "unable to match a supported cipher suite", max);
        break;

    case no_key_file :
        strncpy(buffer, "the server needs a private key file", max);
        break;

    case verify_error :
        strncpy(buffer, "unable to verify peer checksum", max);
        break;

    case send_error :
        strncpy(buffer, "socket layer send error", max);
        break;

    case receive_error :
        strncpy(buffer, "socket layer receive error", max);
        break;

    case certificate_error :
        strncpy(buffer, "unable to proccess cerificate", max);
        break;

    case privateKey_error :
        strncpy(buffer, "unable to proccess private key, bad format", max);
        break;

    case badVersion_error :
        strncpy(buffer, "protocol version mismatch", max);
        break;

    case compress_error :
        strncpy(buffer, "compression error", max);
        break;

    case decompress_error :
        strncpy(buffer, "decompression error", max);
        break;

    case pms_version_error :
        strncpy(buffer, "bad PreMasterSecret version error", max);
        break;

    case sanityCipher_error :
        strncpy(buffer, "sanity check on cipher text size error", max);
        break;

    case rsaSignFault_error:
        strncpy(buffer, "rsa signature fault error", max);
        break;

        // openssl errors
    case SSL_ERROR_WANT_READ :
        strncpy(buffer, "the read operation would block", max);
        break;

    case SSL_ERROR_WANT_WRITE :
        strncpy(buffer, "the write operation would block", max);
        break;

    case CERTFICATE_ERROR :
        strncpy(buffer, "Unable to verify certificate", max);
        break;

        // TaoCrypt errors
    case NO_ERROR_E :
        strncpy(buffer, "not in error state", max);
        break;

    case WINCRYPT_E :
        strncpy(buffer, "bad wincrypt acquire", max);
        break;

    case CRYPTGEN_E :
        strncpy(buffer, "CryptGenRandom error", max);
        break;

    case OPEN_RAN_E :
        strncpy(buffer, "unable to use random device", max);
        break;

    case READ_RAN_E :
        strncpy(buffer, "unable to use random device", max);
        break;

    case INTEGER_E :
        strncpy(buffer, "ASN: bad DER Integer Header", max);
        break;

    case SEQUENCE_E :
        strncpy(buffer, "ASN: bad Sequence Header", max);
        break;

    case SET_E :
        strncpy(buffer, "ASN: bad Set Header", max);
        break;

    case VERSION_E :
        strncpy(buffer, "ASN: version length not 1", max);
        break;

    case SIG_OID_E :
        strncpy(buffer, "ASN: signature OID mismatch", max);
        break;

    case BIT_STR_E :
        strncpy(buffer, "ASN: bad BitString Header", max);
        break;

    case UNKNOWN_OID_E :
        strncpy(buffer, "ASN: unknown key OID type", max);
        break;

    case OBJECT_ID_E :
        strncpy(buffer, "ASN: bad Ojbect ID Header", max);
        break;

    case TAG_NULL_E :
        strncpy(buffer, "ASN: expected TAG NULL", max);
        break;

    case EXPECT_0_E :
        strncpy(buffer, "ASN: expected 0", max);
        break;

    case OCTET_STR_E :
        strncpy(buffer, "ASN: bad Octet String Header", max);
        break;

    case TIME_E :
        strncpy(buffer, "ASN: bad TIME", max);
        break;

    case DATE_SZ_E :
        strncpy(buffer, "ASN: bad Date Size", max);
        break;

    case SIG_LEN_E :
        strncpy(buffer, "ASN: bad Signature Length", max);
        break;

    case UNKOWN_SIG_E :
        strncpy(buffer, "ASN: unknown signature OID", max);
        break;

    case UNKOWN_HASH_E :
        strncpy(buffer, "ASN: unknown hash OID", max);
        break;

    case DSA_SZ_E :
        strncpy(buffer, "ASN: bad DSA r or s size", max);
        break;

    case BEFORE_DATE_E :
        strncpy(buffer, "ASN: before date in the future", max);
        break;

    case AFTER_DATE_E :
        strncpy(buffer, "ASN: after date in the past", max);
        break;

    case SIG_CONFIRM_E :
        strncpy(buffer, "ASN: bad self signature confirmation", max);
        break;

    case SIG_OTHER_E :
        strncpy(buffer, "ASN: bad other signature confirmation", max);
        break;

    case CONTENT_E :
        strncpy(buffer, "bad content processing", max);
        break;

    case PEM_E :
        strncpy(buffer, "bad PEM format processing", max);
        break;

    default :
        strncpy(buffer, "unknown error number", max);
    }
}


void get_xor(byte *digest, uint digLen, output_buffer& md5,
             output_buffer& sha)
{
    for (uint i = 0; i < digLen; i++)
        digest[i] = md5[AUTO] ^ sha[AUTO];
}


static int constant_compare(const byte* a, const byte* b, int len)
{
    int good = 0;
    int bad  = 0;

    for (int i = 0; i < len; i++) {
        if (a[i] == b[i])
            good++;
        else
            bad++;
    }

    if (good == len)
        return 0;
    else
        return 0 - bad;  // failure
}


static int pad_check(const byte* input, byte pad, int len)
{
    int good = 0;
    int bad  = 0;

    for (int i = 0; i < len; i++) {
        if (input[i] == pad)
            good++;
        else
            bad++;
    }

    if (good == len)
        return 0;
    else
        return 0 - bad;  // failure
}


int EncryptedPreMasterSecret::get_length() const
{
    return length_;
}


ContentType Data::get_type() const
{
    return application_data;
}


EncryptedPreMasterSecret::~EncryptedPreMasterSecret()
{
    ysArrayDelete(secret_);
}


CertificateRequest::~CertificateRequest()
{

    STL::for_each(certificate_authorities_.begin(),
                  certificate_authorities_.end(),
                  del_ptr_zero()) ;
}


void ClientDiffieHellmanPublic::alloc(int sz, bool offset)
{
    length_ = sz + (offset ? KEY_OFFSET : 0);
    Yc_ = NEW_YS opaque[length_];
}


void sendCertificate(SSL& ssl, BufferOutput buffer)
{
    if (ssl.GetError()) return;

    Certificate       cert(ssl.getCrypto().get_certManager().get_cert());
    RecordLayerHeader rlHeader;
    HandShakeHeader   hsHeader;
    mySTL::auto_ptr<output_buffer> out(NEW_YS output_buffer);

    buildHeaders(ssl, hsHeader, rlHeader, cert);
    buildOutput(*out.get(), rlHeader, hsHeader, cert);
    hashHandShake(ssl, *out.get());

    if (buffer == buffered)
        ssl.addBuffer(out.release());
    else
        ssl.Send(out->get_buffer(), out->get_size());
}


input_buffer& CertificateVerify::set(input_buffer& in)
{
    return in >> *this;
}


Certificate::Certificate()
    : cert_(0)
{}


void ServerHelloDone::Process(input_buffer& input, SSL& ssl)
{
    if (input.get_error()) {
        ssl.SetError(bad_input);
        return;
    }
    ssl.useStates().useClient() = serverHelloDoneComplete;
}


void PRF(byte* digest, uint digLen, const byte* secret, uint secLen,
         const byte* label, uint labLen, const byte* seed, uint seedLen)
{
    uint half = (secLen + 1) / 2;

    output_buffer md5_half(half);
    output_buffer sha_half(half);
    output_buffer labelSeed(labLen + seedLen);

    md5_half.write(secret, half);
    sha_half.write(secret + half - secLen % 2, half);
    labelSeed.write(label, labLen);
    labelSeed.write(seed, seedLen);

    output_buffer md5_result(digLen);
    output_buffer sha_result(digLen);

    p_hash(md5_result, md5_half, labelSeed, md5);
    p_hash(sha_result, sha_half, labelSeed, sha);

    md5_result.set_current(0);
    sha_result.set_current(0);
    get_xor(digest, digLen, md5_result, sha_result);
}


output_buffer& operator<<(output_buffer& output, const ClientHello& hello)
{
    // Protocol
    output[AUTO] = hello.client_version_.major_;
    output[AUTO] = hello.client_version_.minor_;

    // Random
    output.write(hello.random_, RAN_LEN);

    // Session
    output[AUTO] = hello.id_len_;
    if (hello.id_len_) output.write(hello.session_id_, ID_LEN);

    // Suites
    byte tmp[2];
    c16toa(hello.suite_len_, tmp);
    output[AUTO] = tmp[0];
    output[AUTO] = tmp[1];
    output.write(hello.cipher_suites_, hello.suite_len_);

    // Compression
    output[AUTO] = hello.comp_len_;
    output[AUTO] = hello.compression_methods_;

    return output;
}


output_buffer& operator<<(output_buffer& output, const Finished& fin)
{
    if (fin.get_length() == FINISHED_SZ) {
        output.write(fin.hashes_.md5_, MD5_LEN);
        output.write(fin.hashes_.sha_, SHA_LEN);
    }
    else    // TLS_FINISHED_SZ
        output.write(fin.hashes_.md5_, TLS_FINISHED_SZ);

    return output;
}


void hashHandShake(SSL& ssl, const output_buffer& output, bool removeIV = false)
{
    uint sz = output.get_size() - RECORD_HEADER;

    const opaque* buffer = output.get_buffer() + RECORD_HEADER;

    if (removeIV) {  // TLSv1_1 IV
        uint blockSz = ssl.getCrypto().get_cipher().get_blockSize();
        sz     -= blockSz;
        buffer += blockSz;
    }

    ssl.useHashes().use_MD5().update(buffer, sz);
    ssl.useHashes().use_SHA().update(buffer, sz);
}


void sendCertificateRequest(SSL& ssl, BufferOutput buffer)
{
    if (ssl.GetError()) return;

    CertificateRequest request;
    request.Build();
    RecordLayerHeader  rlHeader;
    HandShakeHeader    hsHeader;
    mySTL::auto_ptr<output_buffer> out(NEW_YS output_buffer);

    buildHeaders(ssl, hsHeader, rlHeader, request);
    buildOutput(*out.get(), rlHeader, hsHeader, request);
    hashHandShake(ssl, *out.get());

    if (buffer == buffered)
        ssl.addBuffer(out.release());
    else
        ssl.Send(out->get_buffer(), out->get_size());
}


input_buffer& Finished::set(input_buffer& in)
{
    return in  >> *this;
}


static int dump_bootstrap_file(char *bootstrap_file)
{
  char *ret= 0;
  int error= 0;
  char query_str[512];
  FILE *file= 0;

  if ((file= fopen(bootstrap_file, "r")) == NULL)
  {
    fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n");
    error= 1;
    goto exit;
  }
  ret= fgets(query_str, 512, file);
  if (ret == 0)
  {
    fprintf(stderr, "ERROR: Cannot read bootstrap file.\n");
    error= 1;
    goto exit;
  }
  printf("# Query: %s\n", query_str);

exit:
  if (file)
  {
    fclose(file);
  }
  return error;
}


static void usage(void)
{
  PRINT_VERSION;
  puts("Copyright (c) 2011, 2015, Oracle and/or its affiliates. "
       "All rights reserved.\n");
  puts("Enable or disable plugins.");
  printf("\nUsage: %s [options] <plugin> ENABLE|DISABLE\n\nOptions:\n",
     my_progname);
  my_print_help(my_long_options);
  puts("\n");
}


static char *get_value(char *line, const char *item)
{
  char *destination= 0;
  int item_len= (int)strlen(item);
  int line_len = (int)strlen(line);

  if ((strncasecmp(line, item, item_len) == 0))
  {
    int start= 0;
    char *s= 0;

    s = line + item_len + 1;
    destination= my_strndup(s, line_len - start, MYF(MY_FAE));
    destination[line_len - item_len - 2]= 0;
  }
  return destination;
}


int main(int argc,char *argv[])
{
  int error= 0;
  char tp_path[FN_REFLEN];
  char server_path[FN_REFLEN];
  char operation[16];

  MY_INIT(argv[0]);
  plugin_data.name= 0; // initialize name

  /*
    The following operations comprise the method for enabling or disabling
    a plugin. We begin by processing the command options then check the
    directories specified for --datadir, --basedir, --plugin-dir, and
    --plugin-ini (if specified). If the directories are Ok, we then look
    for the mysqld executable and the plugin soname. Finally, we build a
    bootstrap command file for use in bootstraping the server.

    If any step fails, the method issues an error message and the tool exits.

      1) Parse, execute, and verify command options.
      2) Check access to directories.
      3) Look for mysqld executable.
      4) Look for the plugin.
      5) Build a bootstrap file with commands to enable or disable plugin.

  */
  if ((error= process_options(argc, argv, operation)) ||
      (error= check_access()) ||
      (error= find_tool("mysqld" FN_EXEEXT, server_path)) ||
      (error= find_plugin(tp_path)) ||
      (error= build_bootstrap_file(operation, bootstrap)))
    goto exit;

  /* Dump the bootstrap file if --verbose specified. */
  if (opt_verbose && ((error= dump_bootstrap_file(bootstrap))))
    goto exit;

  /* Start the server in bootstrap mode and execute bootstrap commands */
  error= bootstrap_server(server_path, bootstrap);

exit:
  /* Remove file */
  my_delete(bootstrap, MYF(0));
  if (opt_verbose && error == 0)
  {
    printf("# Operation succeeded.\n");
  }

  my_end(my_end_arg);
  exit(error ? 1 : 0);
  return 0;        /* No compiler warnings */
}


static int search_dir(const char * base_path, const char *tool_name,
                      const char *subdir, char *tool_path)
{
  char new_path[FN_REFLEN];
  char source_path[FN_REFLEN];

  strcpy(source_path, base_path);
  strcat(source_path, subdir);
  fn_format(new_path, tool_name, source_path, "", MY_UNPACK_FILENAME);
  if (file_exists(new_path))
  {
    strcpy(tool_path, new_path);
    return 1;
  }
  return 0;
}


static int make_tempfile(char *filename, const char *ext)
{
  int fd= 0;

  if ((fd=create_temp_file(filename, NullS, ext, O_CREAT | O_WRONLY,
         MYF(MY_WME))) < 0)
  {
    fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n",
            fd);
    return 1;
  }
  my_close(fd, MYF(0));
  return 0;
}


hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
			   void *font_data,
			   const char *name, int len, /* -1 means nul-terminated */
			   hb_codepoint_t *glyph,
			   void *user_data HB_UNUSED)
{
  /* TODO */
  return false;
}


  inline bool get_extents (hb_codepoint_t glyph,
			   hb_glyph_extents_t *extents) const
  {
    if (unlikely (glyph >= this->num_glyphs))
      return false;

    unsigned int start_offset, end_offset;
    if (this->short_offset)
    {
      start_offset = 2 * this->loca->u.shortsZ[glyph];
      end_offset   = 2 * this->loca->u.shortsZ[glyph + 1];
    }
    else
    {
      start_offset = this->loca->u.longsZ[glyph];
      end_offset   = this->loca->u.longsZ[glyph + 1];
    }

    if (start_offset > end_offset || end_offset > this->glyf_len)
      return false;

    if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
      return true; /* Empty glyph; zero extents. */

    const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset);

    extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
    extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
    extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
    extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;

    return true;
  }


static MYSQL_RES * cli_use_result(MYSQL *mysql)
{
  MYSQL_RES *result;
  DBUG_ENTER("cli_use_result");

  if (!mysql->fields)
    DBUG_RETURN(0);
  if (mysql->status != MYSQL_STATUS_GET_RESULT)
  {
    set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
    DBUG_RETURN(0);
  }
  if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
				      sizeof(ulong)*mysql->field_count,
				      MYF(MY_WME | MY_ZEROFILL))))
    DBUG_RETURN(0);
  result->lengths=(ulong*) (result+1);
  result->methods= mysql->methods;
  if (!(result->row=(MYSQL_ROW)
	my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
  {					/* Ptrs: to one row */
    my_free(result);
    DBUG_RETURN(0);
  }
  result->fields=	mysql->fields;
  result->field_alloc=	mysql->field_alloc;
  result->field_count=	mysql->field_count;
  result->current_field=0;
  result->handle=	mysql;
  result->current_row=	0;
  mysql->fields=0;			/* fields is now in result */
  clear_alloc_root(&mysql->field_alloc);
  mysql->status=MYSQL_STATUS_USE_RESULT;
  mysql->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
  DBUG_RETURN(result);			/* Data is read to be fetched */


my_bool mysql_reconnect(MYSQL *mysql)
{
  MYSQL tmp_mysql;
  DBUG_ENTER("mysql_reconnect");
  DBUG_ASSERT(mysql);
  DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect));

  if (!mysql->reconnect ||
      (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
  {
    /* Allow reconnect next time */
    mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
    set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
    DBUG_RETURN(1);
  }
  mysql_init(&tmp_mysql);
  tmp_mysql.options= mysql->options;
  tmp_mysql.options.my_cnf_file= tmp_mysql.options.my_cnf_group= 0;

  if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
			  mysql->db, mysql->port, mysql->unix_socket,
			  mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
  {
    mysql->net.last_errno= tmp_mysql.net.last_errno;
    strmov(mysql->net.last_error, tmp_mysql.net.last_error);
    strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
    DBUG_RETURN(1);
  }
  if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
  {
    DBUG_PRINT("error", ("mysql_set_character_set() failed"));
    bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options));
    mysql_close(&tmp_mysql);
    mysql->net.last_errno= tmp_mysql.net.last_errno;
    strmov(mysql->net.last_error, tmp_mysql.net.last_error);
    strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
    DBUG_RETURN(1);
  }

  DBUG_PRINT("info", ("reconnect succeded"));
  tmp_mysql.reconnect= 1;
  tmp_mysql.free_me= mysql->free_me;

  /* Move prepared statements (if any) over to the new mysql object */
  tmp_mysql.stmts= mysql->stmts;
  mysql->stmts= 0;

  /* Don't free options as these are now used in tmp_mysql */
  bzero((char*) &mysql->options,sizeof(mysql->options));
  mysql->free_me=0;
  mysql_close(mysql);
  *mysql=tmp_mysql;
  net_clear(&mysql->net, 1);
  mysql->affected_rows= ~(my_ulonglong) 0;
  DBUG_RETURN(0);


HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
{
  ulong smem_buffer_length = shared_memory_buffer_length + 4;
  /*
    event_connect_request is event object for start connection actions
    event_connect_answer is event object for confirm, that server put data
    handle_connect_file_map is file-mapping object, use for create shared
    memory
    handle_connect_map is pointer on shared memory
    handle_map is pointer on shared memory for client
    event_server_wrote,
    event_server_read,
    event_client_wrote,
    event_client_read are events for transfer data between server and client
    handle_file_map is file-mapping object, use for create shared memory
  */
  HANDLE event_connect_request = NULL;
  HANDLE event_connect_answer = NULL;
  HANDLE handle_connect_file_map = NULL;
  char *handle_connect_map = NULL;

  char *handle_map = NULL;
  HANDLE event_server_wrote = NULL;
  HANDLE event_server_read = NULL;
  HANDLE event_client_wrote = NULL;
  HANDLE event_client_read = NULL;
  HANDLE event_conn_closed = NULL;
  HANDLE handle_file_map = NULL;
  ulong connect_number;
  char connect_number_char[22], *p;
  char *tmp= NULL;
  char *suffix_pos;
  DWORD error_allow = 0;
  DWORD error_code = 0;
  DWORD event_access_rights= SYNCHRONIZE | EVENT_MODIFY_STATE;
  char *shared_memory_base_name = mysql->options.shared_memory_base_name;
  static const char *name_prefixes[] = {"","Global\\"};
  const char *prefix;
  int i;

  /*
    If this is NULL, somebody freed the MYSQL* options.  mysql_close()
    is a good candidate.  We don't just silently (re)set it to
    def_shared_memory_base_name as that would create really confusing/buggy
    behavior if the user passed in a different name on the command-line or
    in a my.cnf.
  */
  DBUG_ASSERT(shared_memory_base_name != NULL);

  /*
     get enough space base-name + '_' + longest suffix we might ever send
   */
  if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L, MYF(MY_FAE))))
    goto err;

  /*
    The name of event and file-mapping events create agree next rule:
    shared_memory_base_name+unique_part
    Where:
    shared_memory_base_name is unique value for each server
    unique_part is uniquel value for each object (events and file-mapping)
  */
  for (i = 0; i< array_elements(name_prefixes); i++)
  {
    prefix= name_prefixes[i];
    suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", NullS);
    strmov(suffix_pos, "CONNECT_REQUEST");
    event_connect_request= OpenEvent(event_access_rights, FALSE, tmp);
    if (event_connect_request)
    {
      break;
    }
  }
  if (!event_connect_request)
  {
    error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
    goto err;
  }
  strmov(suffix_pos, "CONNECT_ANSWER");
  if (!(event_connect_answer= OpenEvent(event_access_rights,FALSE,tmp)))
  {
    error_allow = CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR;
    goto err;
  }
  strmov(suffix_pos, "CONNECT_DATA");
  if (!(handle_connect_file_map= OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)))
  {
    error_allow = CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR;
    goto err;
  }
  if (!(handle_connect_map= MapViewOfFile(handle_connect_file_map,
					  FILE_MAP_WRITE,0,0,sizeof(DWORD))))
  {
    error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR;
    goto err;
  }

  /* Send to server request of connection */
  if (!SetEvent(event_connect_request))
  {
    error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
    goto err;
  }

  /* Wait of answer from server */
  if (WaitForSingleObject(event_connect_answer,connect_timeout*1000) !=
      WAIT_OBJECT_0)
  {
    error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR;
    goto err;
  }

  /* Get number of connection */
  connect_number = uint4korr(handle_connect_map);/*WAX2*/
  p= int10_to_str(connect_number, connect_number_char, 10);

  /*
    The name of event and file-mapping events create agree next rule:
    shared_memory_base_name+unique_part+number_of_connection

    Where:
    shared_memory_base_name is uniquel value for each server
    unique_part is uniquel value for each object (events and file-mapping)
    number_of_connection is number of connection between server and client
  */
  suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", connect_number_char,
		       "_", NullS);
  strmov(suffix_pos, "DATA");
  if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)) == NULL)
  {
    error_allow = CR_SHARED_MEMORY_FILE_MAP_ERROR;
    goto err2;
  }
  if ((handle_map = MapViewOfFile(handle_file_map,FILE_MAP_WRITE,0,0,
				  smem_buffer_length)) == NULL)
  {
    error_allow = CR_SHARED_MEMORY_MAP_ERROR;
    goto err2;
  }

  strmov(suffix_pos, "SERVER_WROTE");
  if ((event_server_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
  {
    error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
    goto err2;
  }

  strmov(suffix_pos, "SERVER_READ");
  if ((event_server_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
  {
    error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
    goto err2;
  }

  strmov(suffix_pos, "CLIENT_WROTE");
  if ((event_client_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
  {
    error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
    goto err2;
  }

  strmov(suffix_pos, "CLIENT_READ");
  if ((event_client_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
  {
    error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
    goto err2;
  }

  strmov(suffix_pos, "CONNECTION_CLOSED");
  if ((event_conn_closed = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
  {
    error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
    goto err2;
  }
  /*
    Set event that server should send data
  */
  SetEvent(event_server_read);

err2:
  if (error_allow == 0)
  {
    net->vio= vio_new_win32shared_memory(handle_file_map,handle_map,
                                         event_server_wrote,
                                         event_server_read,event_client_wrote,
                                         event_client_read,event_conn_closed);
  }
  else
  {
    error_code = GetLastError();
    if (event_server_read)
      CloseHandle(event_server_read);
    if (event_server_wrote)
      CloseHandle(event_server_wrote);
    if (event_client_read)
      CloseHandle(event_client_read);
    if (event_client_wrote)
      CloseHandle(event_client_wrote);
    if (event_conn_closed)
      CloseHandle(event_conn_closed);
    if (handle_map)
      UnmapViewOfFile(handle_map);
    if (handle_file_map)
      CloseHandle(handle_file_map);
  }
err:
  my_free(tmp);
  if (error_allow)
    error_code = GetLastError();
  if (event_connect_request)
    CloseHandle(event_connect_request);
  if (event_connect_answer)
    CloseHandle(event_connect_answer);
  if (handle_connect_map)
    UnmapViewOfFile(handle_connect_map);
  if (handle_connect_file_map)
    CloseHandle(handle_connect_file_map);
  if (error_allow)
  {
    if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR)
      set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
                               ER(error_allow), suffix_pos, error_code);
    else
      set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
                               ER(error_allow), error_code);
    return(INVALID_HANDLE_VALUE);
  }
  return(handle_map);
}


*/
static int client_mpvio_write_packet(struct st_plugin_vio *mpv,
                                     const uchar *pkt, int pkt_len)
{
  int res;
  MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;

  if (mpvio->packets_written == 0)
  {
    if (mpvio->mysql_change_user)
      res= send_change_user_packet(mpvio, pkt, pkt_len);
    else
      res= send_client_reply_packet(mpvio, pkt, pkt_len);
  }
  else
  {
    NET *net= &mpvio->mysql->net;
    if (mpvio->mysql->thd)
      res= 1; /* no chit-chat in embedded */
    else
      res= my_net_write(net, pkt, pkt_len) || net_flush(net);
    if (res)
      set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate,
                               ER(CR_SERVER_LOST_EXTENDED),
                               "sending authentication information",
                               errno);
  }
  mpvio->packets_written++;
  return res;


MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql)
{
  MYSQL_RES *result;
  DBUG_ENTER("mysql_store_result");

  if (!mysql->fields)
    DBUG_RETURN(0);
  if (mysql->status != MYSQL_STATUS_GET_RESULT)
  {
    set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
    DBUG_RETURN(0);
  }
  mysql->status=MYSQL_STATUS_READY;		/* server is ready */
  if (!(result=(MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+
					      sizeof(ulong) *
					      mysql->field_count),
				      MYF(MY_WME | MY_ZEROFILL))))
  {
    set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
    DBUG_RETURN(0);
  }
  result->methods= mysql->methods;
  result->eof=1;				/* Marker for buffered */
  result->lengths=(ulong*) (result+1);
  if (!(result->data=
	(*mysql->methods->read_rows)(mysql,mysql->fields,mysql->field_count)))
  {
    my_free(result);
    DBUG_RETURN(0);
  }
  mysql->affected_rows= result->row_count= result->data->rows;
  result->data_cursor=	result->data->data;
  result->fields=	mysql->fields;
  result->field_alloc=	mysql->field_alloc;
  result->field_count=	mysql->field_count;
  /* The rest of result members is bzeroed in malloc */
  mysql->fields=0;				/* fields is now in result */
  clear_alloc_root(&mysql->field_alloc);
  /* just in case this was mistakenly called after mysql_stmt_execute() */
  mysql->unbuffered_fetch_owner= 0;
  DBUG_RETURN(result);				/* Data fetched */


bool SSL_CTX::SetCipherList(const char* list)
{
    if (!list)
        return false;

    bool ret = false;
    char name[MAX_SUITE_NAME];

    char  needle[] = ":";
    char* haystack = const_cast<char*>(list);
    char* prev;

    const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]);
    int idx = 0;

    for(;;) {
        size_t len;
        prev = haystack;
        haystack = strstr(haystack, needle);

        if (!haystack)    // last cipher
            len = min(sizeof(name), strlen(prev));
        else
            len = min(sizeof(name), (size_t)(haystack - prev));

        strncpy(name, prev, len);
        name[(len == sizeof(name)) ? len - 1 : len] = 0;

        for (int i = 0; i < suiteSz; i++)
            if (strncmp(name, cipher_names[i], sizeof(name)) == 0) {

                ciphers_.suites_[idx++] = 0x00;  // first byte always zero
                ciphers_.suites_[idx++] = i;

                if (!ret) ret = true;   // found at least one
                break;
            }
        if (!haystack) break;
        haystack++;
    }

    if (ret) {
        ciphers_.setSuites_ = true;
        ciphers_.suiteSz_ = idx;
    }

    return ret;
}


SSL_METHOD* TLSv1_server_method()
{
    return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,1));
}


const char* SSL_get_version(SSL* ssl)
{
    static const char* version3 =  "SSLv3";
    static const char* version31 = "TLSv1";

    return ssl->isTLS() ? version31 : version3;
}


ConnectionEnd SSL_METHOD::getSide() const
{
    return side_;
}


const char* States::getString() const
{
    return errorString_;
}


AcceptState& States::UseAccept()
{
    return acceptState_;
}


ClientState& States::useClient()
{
    return clientState_;
}


int DES_set_key(const_DES_cblock* key, DES_key_schedule* schedule)
{
    memcpy(schedule, key, sizeof(const_DES_cblock));
    return 1;
}


SSL_SESSION::~SSL_SESSION()
{
    volatile opaque* p = master_secret_;
    clean(p, SECRET_LEN, random_);

    ysDelete(peerX509_);
}


void* X509_get_ext_d2i(X509* x, int nid, int* crit, int* idx)
{
    // no extensions supported yet
    return 0;
}


void Buffers::SetRawInput(input_buffer* ib)
{
    rawInput_ = ib;
}


YasslError SSL::GetError() const
{
    return states_.What();
}


ASN1_TIME* X509_get_notAfter(X509* x)
{
    if (x) return x->GetAfter();
    return 0;
}


void Buffers::SetOutput(output_buffer* ob)
{
    output_ = ob;
}


int ASN1_STRING_length(ASN1_STRING* x)
{
    if (x) return x->length;
    return 0;
}


    int RAND_write_file(const char*)
    {
        // TODO:
        return 0;
    }


ASN1_STRING* StringHolder::GetString()
{
    return &asnString_;
}


Crypto& SSL::useCrypto()
{
    return crypto_;
}


void CertDecoder::DecodeToKey()
{
    ReadHeader();
    signatureOID_ = GetAlgoId();
    GetName(ISSUER);
    GetValidity();
    GetName(SUBJECT);
    GetKey();
}


void SSL::fillData(Data& data)
{
    if (GetError()) return;
    uint dataSz   = data.get_length();        // input, data size to fill
    size_t elements = buffers_.getData().size();

    data.set_length(0);                         // output, actual data filled
    dataSz = min(dataSz, bufferedData());

    for (size_t i = 0; i < elements; i++) {
        input_buffer* front = buffers_.getData().front();
        uint frontSz = front->get_remaining();
        uint readSz  = min(dataSz - data.get_length(), frontSz);

        front->read(data.set_buffer() + data.get_length(), readSz);
        data.set_length(data.get_length() + readSz);

        if (readSz == frontSz) {
            buffers_.useData().pop_front();
            ysDelete(front);
        }
        if (data.get_length() == dataSz)
            break;
    }

    if (buffers_.getData().size() == 0) has_data_ = false;  // none left
}


bool CertDecoder::ValidateSelfSignature()
{
    Source pub(key_.GetKey(), key_.size());
    return ConfirmSignature(pub);
}


const CertManager& Crypto::get_certManager() const
{
    return cert_;
}


void RSA_Private_Decoder::Decode(RSA_PrivateKey& key)
{
    ReadHeader();
    if (source_.GetError().What()) return;
    // public
    key.SetModulus(GetInteger(Integer().Ref()));
    key.SetPublicExponent(GetInteger(Integer().Ref()));

    // private
    key.SetPrivateExponent(GetInteger(Integer().Ref()));
    key.SetPrime1(GetInteger(Integer().Ref()));
    key.SetPrime2(GetInteger(Integer().Ref()));
    key.SetModPrime1PrivateExponent(GetInteger(Integer().Ref()));
    key.SetModPrime2PrivateExponent(GetInteger(Integer().Ref()));
    key.SetMultiplicativeInverseOfPrime2ModPrime1(GetInteger(Integer().Ref()));
}


const Buffers::outputList& Buffers::getHandShake() const
{
    return handShakeList_;
}


long SSL_CTX_sess_number(SSL_CTX* ctx)
{
    return ctx->GetStats().number_;
}


void SSL_CTX::setFailNoCert()
{
    method_->setFailNoCert();
}


bool Crypto::DhSet()
{
    return dh_ != 0;
}


void CertManager::setSendBlankCert()
{
  sendBlankCert_ = true;
}


SSL_METHOD* SSLv23_client_method()
{
    // compatibility only, no version 2 support, but does SSL 3 and TLS 1
    // though it sends TLS1 hello not SSLv2 so SSLv3 only servers will decline
    // TODO: maybe add support to send SSLv2 hello ???
    return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,2), true);
}


const EVP_CIPHER* EVP_des_ede3_cbc(void)
{
    static const char* type = "DES-EDE3-CBC";
    return type;
}


void SSL::makeMasterSecret()
{
    if (GetError()) return;

    if (isTLS())
        makeTLSMasterSecret();
    else {
        opaque sha_output[SHA_LEN];

        const uint& preSz = secure_.get_connection().pre_secret_len_;
        output_buffer md5_input(preSz + SHA_LEN);
        output_buffer sha_input(PREFIX + preSz + 2 * RAN_LEN);

        MD5 md5;
        SHA sha;

        md5_input.write(secure_.get_connection().pre_master_secret_, preSz);

        for (int i = 0; i < MASTER_ROUNDS; ++i) {
            opaque prefix[PREFIX];
            if (!setPrefix(prefix, i)) {
                SetError(prefix_error);
                return;
            }

            sha_input.set_current(0);
            sha_input.write(prefix, i + 1);

            sha_input.write(secure_.get_connection().pre_master_secret_,preSz);
            sha_input.write(secure_.get_connection().client_random_, RAN_LEN);
            sha_input.write(secure_.get_connection().server_random_, RAN_LEN);
            sha.get_digest(sha_output, sha_input.get_buffer(),
                           sha_input.get_size());

            md5_input.set_current(preSz);
            md5_input.write(sha_output, SHA_LEN);
            md5.get_digest(&secure_.use_connection().master_secret_[i*MD5_LEN],
                           md5_input.get_buffer(), md5_input.get_size());
        }
        deriveKeys();
    }
    secure_.use_connection().CleanPreMaster();
}


bool SSL_METHOD::verifyNone() const
{
    return verifyNone_;
}


explicit thr_match() : id_(GetSelf()) {}


void SSL_METHOD::setFailNoCert()
{
    failNoCert_ = true;
}


bool SSL::CompressionOn() const
{
    return secure_.get_connection().compression_;
}


void MD4_Update(MD4_CTX* md4, const void* data, unsigned long sz)
{
    reinterpret_cast<TaoCrypt::MD4*>(md4->buffer)->Update(
                static_cast<const byte*>(data), static_cast<unsigned int>(sz));
}


word32 BER_Decoder::GetSequence()
{
    if (source_.GetError().What()) return 0;

    byte b = source_.next();
    if (b != (SEQUENCE | CONSTRUCTED)) {
        source_.SetError(SEQUENCE_E);
        return 0;
    }

    return GetLength(source_);
}


sslHashes& SSL::useHashes()
{
    return hashes_;
}


void ERR_print_errors_fp(FILE* /*fp*/)
{
    // need ssl access to implement TODO:
    //fprintf(fp, "%s", ssl.get_states().errorString_.c_str());
}


int X509_NAME_get_index_by_NID(X509_NAME* name,int nid, int lastpos)
{
    int idx = -1;  // not found
    int cnPos = -1;

    switch (nid) {
    case NID_commonName:
        cnPos = name->GetCnPosition();
        if (lastpos < cnPos)
            idx = cnPos;
        break;
    }

    return idx;
}


const ClientKeyFactory& sslFactory::getClientKey() const
{
    return clientKeyFactory_;
}


    void SSL_CTX_set_tmp_rsa_callback(SSL_CTX*, RSA*(*)(SSL*, int, int))
    {
        // TDOD:
    }


void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
				unsigned long end, unsigned long vmflag)
{
	unsigned long addr;
	/* do a global flush by default */
	unsigned long base_pages_to_flush = TLB_FLUSH_ALL;

	preempt_disable();
	if (current->active_mm != mm) {
		/* Synchronize with switch_mm. */
		smp_mb();

		goto out;
	}

	if (!current->mm) {
		leave_mm(smp_processor_id());

		/* Synchronize with switch_mm. */
		smp_mb();

		goto out;
	}

	if ((end != TLB_FLUSH_ALL) && !(vmflag & VM_HUGETLB))
		base_pages_to_flush = (end - start) >> PAGE_SHIFT;

	/*
	 * Both branches below are implicit full barriers (MOV to CR or
	 * INVLPG) that synchronize with switch_mm.
	 */
	if (base_pages_to_flush > tlb_single_page_flush_ceiling) {
		base_pages_to_flush = TLB_FLUSH_ALL;
		count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
		local_flush_tlb();
	} else {
		/* flush range by one by one 'invlpg' */
		for (addr = start; addr < end;	addr += PAGE_SIZE) {
			count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ONE);
			__flush_tlb_single(addr);
		}
	}
	trace_tlb_flush(TLB_LOCAL_MM_SHOOTDOWN, base_pages_to_flush);
out:
	if (base_pages_to_flush == TLB_FLUSH_ALL) {
		start = 0UL;
		end = TLB_FLUSH_ALL;
	}
	if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
		flush_tlb_others(mm_cpumask(mm), mm, start, end);
	preempt_enable();
}


static inline void paravirt_activate_mm(struct mm_struct *prev,
					struct mm_struct *next)
{
}


static void do_flush_tlb_all(void *info)
{
	count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
	__flush_tlb_all();
	if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY)
		leave_mm(smp_processor_id());
}


static inline void load_mm_ldt(struct mm_struct *mm)
{
#ifdef CONFIG_MODIFY_LDT_SYSCALL
	struct ldt_struct *ldt;

	/* lockless_dereference synchronizes with smp_store_release */
	ldt = lockless_dereference(mm->context.ldt);

	/*
	 * Any change to mm->context.ldt is followed by an IPI to all
	 * CPUs with the mm active.  The LDT will not be freed until
	 * after the IPI is handled by all such CPUs.  This means that,
	 * if the ldt_struct changes before we return, the values we see
	 * will be safe, and the new values will be loaded before we run
	 * any user code.
	 *
	 * NB: don't try to convert this to use RCU without extreme care.
	 * We would still need IRQs off, because we don't want to change
	 * the local LDT after an IPI loaded a newer value than the one
	 * that we can see.
	 */

	if (unlikely(ldt))
		set_ldt(ldt->entries, ldt->size);
	else
		clear_LDT();
#else
	clear_LDT();
#endif

	DEBUG_LOCKS_WARN_ON(preemptible());
}


unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
			int tag, unsigned int nr_pages, struct page **pages)
{
	unsigned int i;
	unsigned int ret;

	read_lock_irq(&mapping->tree_lock);
	ret = radix_tree_gang_lookup_tag(&mapping->page_tree,
				(void **)pages, *index, nr_pages, tag);
	for (i = 0; i < ret; i++)
		page_cache_get(pages[i]);
	if (ret)
		*index = pages[ret - 1]->index + 1;
	read_unlock_irq(&mapping->tree_lock);
	return ret;
}


static int fastcall page_cache_read(struct file * file, pgoff_t offset)
{
	struct address_space *mapping = file->f_mapping;
	struct page *page;
	int ret;

	do {
		page = page_cache_alloc_cold(mapping);
		if (!page)
			return -ENOMEM;

		ret = add_to_page_cache_lru(page, mapping, offset, GFP_KERNEL);
		if (ret == 0)
			ret = mapping->a_ops->readpage(file, page);
		else if (ret == -EEXIST)
			ret = 0; /* losing race to add is OK */

		page_cache_release(page);

	} while (ret == AOP_TRUNCATED_PAGE);

	return ret;
}


void tcp_rearm_rto(struct sock *sk)
{
	const struct inet_connection_sock *icsk = inet_csk(sk);
	struct tcp_sock *tp = tcp_sk(sk);

	/* If the retrans timer is currently being used by Fast Open
	 * for SYN-ACK retrans purpose, stay put.
	 */
	if (tp->fastopen_rsk)
		return;

	if (!tp->packets_out) {
		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
	} else {
		u32 rto = inet_csk(sk)->icsk_rto;
		/* Offset the time elapsed after installing regular RTO */
		if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
		    icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
			struct sk_buff *skb = tcp_write_queue_head(sk);
			const u32 rto_time_stamp =
				tcp_skb_timestamp(skb) + rto;
			s32 delta = (s32)(rto_time_stamp - tcp_time_stamp);
			/* delta may not be positive if the socket is locked
			 * when the retrans timer fires and is rescheduled.
			 */
			if (delta > 0)
				rto = delta;
		}
		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto,
					  TCP_RTO_MAX);
	}
}


static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
			       u32 prior_snd_una,
			       struct tcp_sacktag_state *sack)
{
	const struct inet_connection_sock *icsk = inet_csk(sk);
	struct skb_mstamp first_ackt, last_ackt, now;
	struct tcp_sock *tp = tcp_sk(sk);
	u32 prior_sacked = tp->sacked_out;
	u32 reord = tp->packets_out;
	bool fully_acked = true;
	long sack_rtt_us = -1L;
	long seq_rtt_us = -1L;
	long ca_rtt_us = -1L;
	struct sk_buff *skb;
	u32 pkts_acked = 0;
	bool rtt_update;
	int flag = 0;

	first_ackt.v64 = 0;

	while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) {
		struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
		u8 sacked = scb->sacked;
		u32 acked_pcount;

		tcp_ack_tstamp(sk, skb, prior_snd_una);

		/* Determine how many packets and what bytes were acked, tso and else */
		if (after(scb->end_seq, tp->snd_una)) {
			if (tcp_skb_pcount(skb) == 1 ||
			    !after(tp->snd_una, scb->seq))
				break;

			acked_pcount = tcp_tso_acked(sk, skb);
			if (!acked_pcount)
				break;

			fully_acked = false;
		} else {
			/* Speedup tcp_unlink_write_queue() and next loop */
			prefetchw(skb->next);
			acked_pcount = tcp_skb_pcount(skb);
		}

		if (unlikely(sacked & TCPCB_RETRANS)) {
			if (sacked & TCPCB_SACKED_RETRANS)
				tp->retrans_out -= acked_pcount;
			flag |= FLAG_RETRANS_DATA_ACKED;
		} else if (!(sacked & TCPCB_SACKED_ACKED)) {
			last_ackt = skb->skb_mstamp;
			WARN_ON_ONCE(last_ackt.v64 == 0);
			if (!first_ackt.v64)
				first_ackt = last_ackt;

			reord = min(pkts_acked, reord);
			if (!after(scb->end_seq, tp->high_seq))
				flag |= FLAG_ORIG_SACK_ACKED;
		}

		if (sacked & TCPCB_SACKED_ACKED)
			tp->sacked_out -= acked_pcount;
		else if (tcp_is_sack(tp) && !tcp_skb_spurious_retrans(tp, skb))
			tcp_rack_advance(tp, &skb->skb_mstamp, sacked);
		if (sacked & TCPCB_LOST)
			tp->lost_out -= acked_pcount;

		tp->packets_out -= acked_pcount;
		pkts_acked += acked_pcount;

		/* Initial outgoing SYN's get put onto the write_queue
		 * just like anything else we transmit.  It is not
		 * true data, and if we misinform our callers that
		 * this ACK acks real data, we will erroneously exit
		 * connection startup slow start one packet too
		 * quickly.  This is severely frowned upon behavior.
		 */
		if (likely(!(scb->tcp_flags & TCPHDR_SYN))) {
			flag |= FLAG_DATA_ACKED;
		} else {
			flag |= FLAG_SYN_ACKED;
			tp->retrans_stamp = 0;
		}

		if (!fully_acked)
			break;

		tcp_unlink_write_queue(skb, sk);
		sk_wmem_free_skb(sk, skb);
		if (unlikely(skb == tp->retransmit_skb_hint))
			tp->retransmit_skb_hint = NULL;
		if (unlikely(skb == tp->lost_skb_hint))
			tp->lost_skb_hint = NULL;
	}

	if (likely(between(tp->snd_up, prior_snd_una, tp->snd_una)))
		tp->snd_up = tp->snd_una;

	if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
		flag |= FLAG_SACK_RENEGING;

	skb_mstamp_get(&now);
	if (likely(first_ackt.v64) && !(flag & FLAG_RETRANS_DATA_ACKED)) {
		seq_rtt_us = skb_mstamp_us_delta(&now, &first_ackt);
		ca_rtt_us = skb_mstamp_us_delta(&now, &last_ackt);
	}
	if (sack->first_sackt.v64) {
		sack_rtt_us = skb_mstamp_us_delta(&now, &sack->first_sackt);
		ca_rtt_us = skb_mstamp_us_delta(&now, &sack->last_sackt);
	}

	rtt_update = tcp_ack_update_rtt(sk, flag, seq_rtt_us, sack_rtt_us,
					ca_rtt_us);

	if (flag & FLAG_ACKED) {
		tcp_rearm_rto(sk);
		if (unlikely(icsk->icsk_mtup.probe_size &&
			     !after(tp->mtu_probe.probe_seq_end, tp->snd_una))) {
			tcp_mtup_probe_success(sk);
		}

		if (tcp_is_reno(tp)) {
			tcp_remove_reno_sacks(sk, pkts_acked);
		} else {
			int delta;

			/* Non-retransmitted hole got filled? That's reordering */
			if (reord < prior_fackets)
				tcp_update_reordering(sk, tp->fackets_out - reord, 0);

			delta = tcp_is_fack(tp) ? pkts_acked :
						  prior_sacked - tp->sacked_out;
			tp->lost_cnt_hint -= min(tp->lost_cnt_hint, delta);
		}

		tp->fackets_out -= min(pkts_acked, tp->fackets_out);

	} else if (skb && rtt_update && sack_rtt_us >= 0 &&
		   sack_rtt_us > skb_mstamp_us_delta(&now, &skb->skb_mstamp)) {
		/* Do not re-arm RTO if the sack RTT is measured from data sent
		 * after when the head was last (re)transmitted. Otherwise the
		 * timeout may continue to extend in loss recovery.
		 */
		tcp_rearm_rto(sk);
	}

	if (icsk->icsk_ca_ops->pkts_acked)
		icsk->icsk_ca_ops->pkts_acked(sk, pkts_acked, ca_rtt_us);

#if FASTRETRANS_DEBUG > 0
	WARN_ON((int)tp->sacked_out < 0);
	WARN_ON((int)tp->lost_out < 0);
	WARN_ON((int)tp->retrans_out < 0);
	if (!tp->packets_out && tcp_is_sack(tp)) {
		icsk = inet_csk(sk);
		if (tp->lost_out) {
			pr_debug("Leak l=%u %d\n",
				 tp->lost_out, icsk->icsk_ca_state);
			tp->lost_out = 0;
		}
		if (tp->sacked_out) {
			pr_debug("Leak s=%u %d\n",
				 tp->sacked_out, icsk->icsk_ca_state);
			tp->sacked_out = 0;
		}
		if (tp->retrans_out) {
			pr_debug("Leak r=%u %d\n",
				 tp->retrans_out, icsk->icsk_ca_state);
			tp->retrans_out = 0;
		}
	}
#endif
	return flag;
}


struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
				      struct sock *sk_listener,
				      bool attach_listener)
{
	struct request_sock *req = reqsk_alloc(ops, sk_listener,
					       attach_listener);

	if (req) {
		struct inet_request_sock *ireq = inet_rsk(req);

		kmemcheck_annotate_bitfield(ireq, flags);
		ireq->opt = NULL;
		atomic64_set(&ireq->ir_cookie, 0);
		ireq->ireq_state = TCP_NEW_SYN_RECV;
		write_pnet(&ireq->ireq_net, sock_net(sk_listener));
		ireq->ireq_family = sk_listener->sk_family;
	}

	return req;
}


static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack)
{
	struct tcp_sock *tp = tcp_sk(sk);
	bool recovered = !before(tp->snd_una, tp->high_seq);

	if ((flag & FLAG_SND_UNA_ADVANCED) &&
	    tcp_try_undo_loss(sk, false))
		return;

	if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */
		/* Step 3.b. A timeout is spurious if not all data are
		 * lost, i.e., never-retransmitted data are (s)acked.
		 */
		if ((flag & FLAG_ORIG_SACK_ACKED) &&
		    tcp_try_undo_loss(sk, true))
			return;

		if (after(tp->snd_nxt, tp->high_seq)) {
			if (flag & FLAG_DATA_SACKED || is_dupack)
				tp->frto = 0; /* Step 3.a. loss was real */
		} else if (flag & FLAG_SND_UNA_ADVANCED && !recovered) {
			tp->high_seq = tp->snd_nxt;
			__tcp_push_pending_frames(sk, tcp_current_mss(sk),
						  TCP_NAGLE_OFF);
			if (after(tp->snd_nxt, tp->high_seq))
				return; /* Step 2.b */
			tp->frto = 0;
		}
	}

	if (recovered) {
		/* F-RTO RFC5682 sec 3.1 step 2.a and 1st part of step 3.a */
		tcp_try_undo_recovery(sk);
		return;
	}
	if (tcp_is_reno(tp)) {
		/* A Reno DUPACK means new data in F-RTO step 2.b above are
		 * delivered. Lower inflight to clock out (re)tranmissions.
		 */
		if (after(tp->snd_nxt, tp->high_seq) && is_dupack)
			tcp_add_reno_sack(sk);
		else if (flag & FLAG_SND_UNA_ADVANCED)
			tcp_reset_reno_sack(tp);
	}
	tcp_xmit_retransmit_queue(sk);
}


static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack)
{
	u32 delta = ack - tp->snd_una;

	u64_stats_update_begin(&tp->syncp);
	tp->bytes_acked += delta;
	u64_stats_update_end(&tp->syncp);
	tp->snd_una = ack;
}


void tcp_enter_cwr(struct sock *sk)
{
	struct tcp_sock *tp = tcp_sk(sk);

	tp->prior_ssthresh = 0;
	if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) {
		tp->undo_marker = 0;
		tcp_init_cwnd_reduction(sk);
		tcp_set_ca_state(sk, TCP_CA_CWR);
	}
}


static void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
{
	if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
		/* PAWS bug workaround wrt. ACK frames, the PAWS discard
		 * extra check below makes sure this can only happen
		 * for pure ACK frames.  -DaveM
		 *
		 * Not only, also it occurs for expired timestamps.
		 */

		if (tcp_paws_check(&tp->rx_opt, 0))
			tcp_store_ts_recent(tp);
	}
}


static u8 tcp_sacktag_one(struct sock *sk,
			  struct tcp_sacktag_state *state, u8 sacked,
			  u32 start_seq, u32 end_seq,
			  int dup_sack, int pcount,
			  const struct skb_mstamp *xmit_time)
{
	struct tcp_sock *tp = tcp_sk(sk);
	int fack_count = state->fack_count;

	/* Account D-SACK for retransmitted packet. */
	if (dup_sack && (sacked & TCPCB_RETRANS)) {
		if (tp->undo_marker && tp->undo_retrans > 0 &&
		    after(end_seq, tp->undo_marker))
			tp->undo_retrans--;
		if (sacked & TCPCB_SACKED_ACKED)
			state->reord = min(fack_count, state->reord);
	}

	/* Nothing to do; acked frame is about to be dropped (was ACKed). */
	if (!after(end_seq, tp->snd_una))
		return sacked;

	if (!(sacked & TCPCB_SACKED_ACKED)) {
		tcp_rack_advance(tp, xmit_time, sacked);

		if (sacked & TCPCB_SACKED_RETRANS) {
			/* If the segment is not tagged as lost,
			 * we do not clear RETRANS, believing
			 * that retransmission is still in flight.
			 */
			if (sacked & TCPCB_LOST) {
				sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
				tp->lost_out -= pcount;
				tp->retrans_out -= pcount;
			}
		} else {
			if (!(sacked & TCPCB_RETRANS)) {
				/* New sack for not retransmitted frame,
				 * which was in hole. It is reordering.
				 */
				if (before(start_seq,
					   tcp_highest_sack_seq(tp)))
					state->reord = min(fack_count,
							   state->reord);
				if (!after(end_seq, tp->high_seq))
					state->flag |= FLAG_ORIG_SACK_ACKED;
				if (state->first_sackt.v64 == 0)
					state->first_sackt = *xmit_time;
				state->last_sackt = *xmit_time;
			}

			if (sacked & TCPCB_LOST) {
				sacked &= ~TCPCB_LOST;
				tp->lost_out -= pcount;
			}
		}

		sacked |= TCPCB_SACKED_ACKED;
		state->flag |= FLAG_DATA_SACKED;
		tp->sacked_out += pcount;

		fack_count += pcount;

		/* Lost marker hint past SACKed? Tweak RFC3517 cnt */
		if (!tcp_is_fack(tp) && tp->lost_skb_hint &&
		    before(start_seq, TCP_SKB_CB(tp->lost_skb_hint)->seq))
			tp->lost_cnt_hint += pcount;

		if (fack_count > tp->fackets_out)
			tp->fackets_out = fack_count;
	}

	/* D-SACK. We can detect redundant retransmission in S|R and plain R
	 * frames and clear it. undo_retrans is decreased above, L|R frames
	 * are accounted above as well.
	 */
	if (dup_sack && (sacked & TCPCB_SACKED_RETRANS)) {
		sacked &= ~TCPCB_SACKED_RETRANS;
		tp->retrans_out -= pcount;
	}

	return sacked;
}


static void tcp_ack_tstamp(struct sock *sk, struct sk_buff *skb,
			   u32 prior_snd_una)
{
	const struct skb_shared_info *shinfo;

	/* Avoid cache line misses to get skb_shinfo() and shinfo->tx_flags */
	if (likely(!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK)))
		return;

	shinfo = skb_shinfo(skb);
	if ((shinfo->tx_flags & SKBTX_ACK_TSTAMP) &&
	    between(shinfo->tskey, prior_snd_una, tcp_sk(sk)->snd_una - 1))
		__skb_tstamp_tx(skb, NULL, sk, SCM_TSTAMP_ACK);
}


static inline void pr_drop_req(struct request_sock *req, __u16 port, int family)
{
	struct inet_request_sock *ireq = inet_rsk(req);

	if (family == AF_INET)
		net_dbg_ratelimited("drop open request from %pI4/%u\n",
				    &ireq->ir_rmt_addr, port);
#if IS_ENABLED(CONFIG_IPV6)
	else if (family == AF_INET6)
		net_dbg_ratelimited("drop open request from %pI6/%u\n",
				    &ireq->ir_v6_rmt_addr, port);
#endif
}


static void tcp_openreq_init(struct request_sock *req,
			     const struct tcp_options_received *rx_opt,
			     struct sk_buff *skb, const struct sock *sk)
{
	struct inet_request_sock *ireq = inet_rsk(req);

	req->rsk_rcv_wnd = 0;		/* So that tcp_send_synack() knows! */
	req->cookie_ts = 0;
	tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
	tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
	skb_mstamp_get(&tcp_rsk(req)->snt_synack);
	tcp_rsk(req)->last_oow_ack_time = 0;
	req->mss = rx_opt->mss_clamp;
	req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0;
	ireq->tstamp_ok = rx_opt->tstamp_ok;
	ireq->sack_ok = rx_opt->sack_ok;
	ireq->snd_wscale = rx_opt->snd_wscale;
	ireq->wscale_ok = rx_opt->wscale_ok;
	ireq->acked = 0;
	ireq->ecn_ok = 0;
	ireq->ir_rmt_port = tcp_hdr(skb)->source;
	ireq->ir_num = ntohs(tcp_hdr(skb)->dest);
	ireq->ir_mark = inet_request_mark(sk, skb);
}


int tcp_conn_request(struct request_sock_ops *rsk_ops,
		     const struct tcp_request_sock_ops *af_ops,
		     struct sock *sk, struct sk_buff *skb)
{
	struct tcp_fastopen_cookie foc = { .len = -1 };
	__u32 isn = TCP_SKB_CB(skb)->tcp_tw_isn;
	struct tcp_options_received tmp_opt;
	struct tcp_sock *tp = tcp_sk(sk);
	struct sock *fastopen_sk = NULL;
	struct dst_entry *dst = NULL;
	struct request_sock *req;
	bool want_cookie = false;
	struct flowi fl;

	/* TW buckets are converted to open requests without
	 * limitations, they conserve resources and peer is
	 * evidently real one.
	 */
	if ((sysctl_tcp_syncookies == 2 ||
	     inet_csk_reqsk_queue_is_full(sk)) && !isn) {
		want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name);
		if (!want_cookie)
			goto drop;
	}

	/* Accept backlog is full. If we have already queued enough
	 * of warm entries in syn queue, drop request. It is better than
	 * clogging syn queue with openreqs with exponentially increasing
	 * timeout.
	 */
	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
		goto drop;
	}

	req = inet_reqsk_alloc(rsk_ops, sk, !want_cookie);
	if (!req)
		goto drop;

	tcp_rsk(req)->af_specific = af_ops;

	tcp_clear_options(&tmp_opt);
	tmp_opt.mss_clamp = af_ops->mss_clamp;
	tmp_opt.user_mss  = tp->rx_opt.user_mss;
	tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc);

	if (want_cookie && !tmp_opt.saw_tstamp)
		tcp_clear_options(&tmp_opt);

	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
	tcp_openreq_init(req, &tmp_opt, skb, sk);

	/* Note: tcp_v6_init_req() might override ir_iif for link locals */
	inet_rsk(req)->ir_iif = sk->sk_bound_dev_if;

	af_ops->init_req(req, sk, skb);

	if (security_inet_conn_request(sk, skb, req))
		goto drop_and_free;

	if (!want_cookie && !isn) {
		/* VJ's idea. We save last timestamp seen
		 * from the destination in peer table, when entering
		 * state TIME-WAIT, and check against it before
		 * accepting new connection request.
		 *
		 * If "isn" is not zero, this request hit alive
		 * timewait bucket, so that all the necessary checks
		 * are made in the function processing timewait state.
		 */
		if (tcp_death_row.sysctl_tw_recycle) {
			bool strict;

			dst = af_ops->route_req(sk, &fl, req, &strict);

			if (dst && strict &&
			    !tcp_peer_is_proven(req, dst, true,
						tmp_opt.saw_tstamp)) {
				NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
				goto drop_and_release;
			}
		}
		/* Kill the following clause, if you dislike this way. */
		else if (!sysctl_tcp_syncookies &&
			 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
			  (sysctl_max_syn_backlog >> 2)) &&
			 !tcp_peer_is_proven(req, dst, false,
					     tmp_opt.saw_tstamp)) {
			/* Without syncookies last quarter of
			 * backlog is filled with destinations,
			 * proven to be alive.
			 * It means that we continue to communicate
			 * to destinations, already remembered
			 * to the moment of synflood.
			 */
			pr_drop_req(req, ntohs(tcp_hdr(skb)->source),
				    rsk_ops->family);
			goto drop_and_release;
		}

		isn = af_ops->init_seq(skb);
	}
	if (!dst) {
		dst = af_ops->route_req(sk, &fl, req, NULL);
		if (!dst)
			goto drop_and_free;
	}

	tcp_ecn_create_request(req, skb, sk, dst);

	if (want_cookie) {
		isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
		req->cookie_ts = tmp_opt.tstamp_ok;
		if (!tmp_opt.tstamp_ok)
			inet_rsk(req)->ecn_ok = 0;
	}

	tcp_rsk(req)->snt_isn = isn;
	tcp_rsk(req)->txhash = net_tx_rndhash();
	tcp_openreq_init_rwin(req, sk, dst);
	if (!want_cookie) {
		tcp_reqsk_record_syn(sk, req, skb);
		fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst);
	}
	if (fastopen_sk) {
		af_ops->send_synack(fastopen_sk, dst, &fl, req,
				    &foc, false);
		/* Add the child socket directly into the accept queue */
		inet_csk_reqsk_queue_add(sk, req, fastopen_sk);
		sk->sk_data_ready(sk);
		bh_unlock_sock(fastopen_sk);
		sock_put(fastopen_sk);
	} else {
		tcp_rsk(req)->tfo_listener = false;
		if (!want_cookie)
			inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
		af_ops->send_synack(sk, dst, &fl, req,
				    &foc, !want_cookie);
		if (want_cookie)
			goto drop_and_free;
	}
	reqsk_put(req);
	return 0;

drop_and_release:
	dst_release(dst);
drop_and_free:
	reqsk_free(req);
drop:
	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
	return 0;
}


static size_t max_pipeline_length(struct Curl_multi *multi)
{
  return multi ? multi->max_pipeline_length : 0;
}


rqst2name(struct svc_req *rqstp)
{

    if (rqstp->rq_cred.oa_flavor == RPCSEC_GSS)
        return rqstp->rq_clntname;
    else
        return rqstp->rq_clntcred;
}