static inline struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk,
					 const union tcp_md5_addr *addr,
					 int family)
{
	return NULL;
}

extern struct inet_hashinfo tcp_hashinfo;

extern struct percpu_counter tcp_orphan_count;

void tcp_time_wait(struct sock *sk, int state, int timeo);

extern struct inet_timewait_death_row tcp_death_row;

extern int sysctl_tcp_timestamps;

extern int sysctl_tcp_window_scaling;

extern int sysctl_tcp_sack;

extern int sysctl_tcp_fastopen;

extern int sysctl_tcp_retrans_collapse;

extern int sysctl_tcp_stdurg;

extern int sysctl_tcp_rfc1337;

extern int sysctl_tcp_abort_on_overflow;

extern int sysctl_tcp_max_orphans;

extern int sysctl_tcp_fack;

extern int sysctl_tcp_reordering;

extern int sysctl_tcp_max_reordering;

extern int sysctl_tcp_dsack;

extern int sysctl_tcp_wmem[3];

extern int sysctl_tcp_rmem[3];

extern int sysctl_tcp_app_win;

extern int sysctl_tcp_adv_win_scale;

extern int sysctl_tcp_tw_reuse;

extern int sysctl_tcp_frto;

extern int sysctl_tcp_low_latency;

extern int sysctl_tcp_nometrics_save;

extern int sysctl_tcp_moderate_rcvbuf;

extern int sysctl_tcp_tso_win_divisor;

extern int sysctl_tcp_workaround_signed_windows;

extern int sysctl_tcp_slow_start_after_idle;

extern int sysctl_tcp_thin_linear_timeouts;

extern int sysctl_tcp_thin_dupack;

extern int sysctl_tcp_early_retrans;

extern int sysctl_tcp_limit_output_bytes;

extern int sysctl_tcp_challenge_ack_limit;

extern int sysctl_tcp_min_tso_segs;

extern int sysctl_tcp_min_rtt_wlen;

extern int sysctl_tcp_autocorking;

extern int sysctl_tcp_invalid_ratelimit;

extern int sysctl_tcp_pacing_ss_ratio;

extern int sysctl_tcp_pacing_ca_ratio;

extern struct percpu_counter tcp_sockets_allocated;

extern int tcp_memory_pressure;

void sk_forced_mem_schedule(struct sock *sk, int size);

bool tcp_check_oom(struct sock *sk, int shift);

extern struct proto tcp_prot;

void tcp_v4_err(struct sk_buff *skb, u32);

void tcp_shutdown(struct sock *sk, int how);

void tcp_v4_early_demux(struct sk_buff *skb);

int tcp_v4_rcv(struct sk_buff *skb);

int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);

int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);

int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
		 int flags);

void tcp_release_cb(struct sock *sk);

void tcp_wfree(struct sk_buff *skb);

void tcp_write_timer_handler(struct sock *sk);

void tcp_delack_timer_handler(struct sock *sk);

int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);

void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
			 const struct tcphdr *th, unsigned int len);

void tcp_rcv_space_adjust(struct sock *sk);

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);

void tcp_twsk_destructor(struct sock *sk);

ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
			struct pipe_inode_info *pipe, size_t len,
			unsigned int flags);

enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
					      struct sk_buff *skb,
					      const struct tcphdr *th);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
			   struct request_sock *req, bool fastopen);


static inline void tcp_slow_start_after_idle_check(struct sock *sk)
{
	struct tcp_sock *tp = tcp_sk(sk);
	s32 delta;

	if (!sysctl_tcp_slow_start_after_idle || tp->packets_out)
		return;
	delta = tcp_time_stamp - tp->lsndtime;
	if (delta > inet_csk(sk)->icsk_rto)
		tcp_cwnd_restart(sk, delta);
}

tcp: fix use after free in tcp_xmit_retransmit_queue()

When tcp_sendmsg() allocates a fresh and empty skb, it puts it at the
tail of the write queue using tcp_add_write_queue_tail()

Then it attempts to copy user data into this fresh skb.

If the copy fails, we undo the work and remove the fresh skb.

Unfortunately, this undo lacks the change done to tp->highest_sack and
we can leave a dangling pointer (to a freed skb)

Later, tcp_xmit_retransmit_queue() can dereference this pointer and
access freed memory. For regular kernels where memory is not unmapped,
this might cause SACK bugs because tcp_highest_sack_seq() is buggy,
returning garbage instead of tp->snd_nxt, but with various debug
features like CONFIG_DEBUG_PAGEALLOC, this can crash the kernel.

This bug was found by Marco Grassi thanks to syzkaller.

Fixes: 6859d49475d4 ("[TCP]: Abstract tp->highest_sack accessing & point to next skb")
Reported-by: Marco Grassi <marco.gra@gmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
Reviewed-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

extern struct inet_hashinfo tcp_hashinfo;

extern struct percpu_counter tcp_orphan_count;

void tcp_time_wait(struct sock *sk, int state, int timeo);

extern struct inet_timewait_death_row tcp_death_row;

extern int sysctl_tcp_slow_start_after_idle;

extern struct percpu_counter tcp_sockets_allocated;

void sk_forced_mem_schedule(struct sock *sk, int size);

bool tcp_check_oom(struct sock *sk, int shift);

extern struct proto tcp_prot;

void tcp_tasklet_init(void);

void tcp_v4_err(struct sk_buff *skb, u32);

void tcp_shutdown(struct sock *sk, int how);

void tcp_v4_early_demux(struct sk_buff *skb);

int tcp_v4_rcv(struct sk_buff *skb);

int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);

int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);

int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
		 int flags);

void tcp_release_cb(struct sock *sk);

void tcp_wfree(struct sk_buff *skb);

void tcp_write_timer_handler(struct sock *sk);

void tcp_delack_timer_handler(struct sock *sk);

int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);

void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
			 const struct tcphdr *th, unsigned int len);

void tcp_rcv_space_adjust(struct sock *sk);

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);

void tcp_twsk_destructor(struct sock *sk);

ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
			struct pipe_inode_info *pipe, size_t len,
			unsigned int flags);

enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
					      struct sk_buff *skb,
					      const struct tcphdr *th);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
			   struct request_sock *req, bool fastopen);

int tcp_child_process(struct sock *parent, struct sock *child,
		      struct sk_buff *skb);

void tcp_enter_loss(struct sock *sk);

void tcp_clear_retrans(struct tcp_sock *tp);

void tcp_update_metrics(struct sock *sk);

void tcp_init_metrics(struct sock *sk);

void tcp_metrics_init(void);

bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst,
			bool paws_check, bool timestamps);

bool tcp_remember_stamp(struct sock *sk);

bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw);

void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst);

void tcp_disable_fack(struct tcp_sock *tp);

void tcp_close(struct sock *sk, long timeout);

void tcp_init_sock(struct sock *sk);

unsigned int tcp_poll(struct file *file, struct socket *sock,
		      struct poll_table_struct *wait);

int tcp_getsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, int __user *optlen);

int tcp_setsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, unsigned int optlen);

int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, int __user *optlen);

int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, unsigned int optlen);

void tcp_set_keepalive(struct sock *sk, int val);

void tcp_syn_ack_timeout(const struct request_sock *req);


static inline u32 tcp_skb_timestamp(const struct sk_buff *skb)
{
	return skb->skb_mstamp.stamp_jiffies;
}

extern struct inet_hashinfo tcp_hashinfo;

extern struct percpu_counter tcp_orphan_count;

void tcp_time_wait(struct sock *sk, int state, int timeo);

extern struct inet_timewait_death_row tcp_death_row;

extern struct percpu_counter tcp_sockets_allocated;

void sk_forced_mem_schedule(struct sock *sk, int size);

bool tcp_check_oom(struct sock *sk, int shift);

extern struct proto tcp_prot;

void tcp_v4_err(struct sk_buff *skb, u32);

void tcp_shutdown(struct sock *sk, int how);

void tcp_v4_early_demux(struct sk_buff *skb);

int tcp_v4_rcv(struct sk_buff *skb);

int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);

int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);

int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
		 int flags);

void tcp_release_cb(struct sock *sk);

void tcp_wfree(struct sk_buff *skb);

void tcp_write_timer_handler(struct sock *sk);

void tcp_delack_timer_handler(struct sock *sk);

int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);

void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
			 const struct tcphdr *th, unsigned int len);

void tcp_rcv_space_adjust(struct sock *sk);

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);

void tcp_twsk_destructor(struct sock *sk);

ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
			struct pipe_inode_info *pipe, size_t len,
			unsigned int flags);

enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
					      struct sk_buff *skb,
					      const struct tcphdr *th);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
			   struct request_sock *req, bool fastopen);

int tcp_child_process(struct sock *parent, struct sock *child,
		      struct sk_buff *skb);

void tcp_enter_loss(struct sock *sk);

void tcp_clear_retrans(struct tcp_sock *tp);

void tcp_update_metrics(struct sock *sk);

void tcp_init_metrics(struct sock *sk);

bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst,
			bool paws_check, bool timestamps);

bool tcp_remember_stamp(struct sock *sk);

bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw);

void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst);

void tcp_disable_fack(struct tcp_sock *tp);

void tcp_close(struct sock *sk, long timeout);

void tcp_init_sock(struct sock *sk);

unsigned int tcp_poll(struct file *file, struct socket *sock,
		      struct poll_table_struct *wait);

int tcp_getsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, int __user *optlen);

int tcp_setsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, unsigned int optlen);

int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, int __user *optlen);

int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, unsigned int optlen);

void tcp_set_keepalive(struct sock *sk, int val);

void tcp_syn_ack_timeout(const struct request_sock *req);


static inline bool tcp_is_reno(const struct tcp_sock *tp)
{
	return !tcp_is_sack(tp);
}


static inline bool tcp_skb_can_collapse_to(const struct sk_buff *skb)
{
	return likely(!TCP_SKB_CB(skb)->eor);
}

extern struct inet_hashinfo tcp_hashinfo;

extern struct percpu_counter tcp_orphan_count;

void tcp_time_wait(struct sock *sk, int state, int timeo);

#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ))	/* RFC 1122 initial RTO value, now
						 * used as a fallback RTO for the
						 * initial data transmission if no
						 * valid RTT sample has been acquired,
						 * most likely due to retrans in 3WHS.
						 */

extern struct inet_timewait_death_row tcp_death_row;

extern struct percpu_counter tcp_sockets_allocated;

void sk_forced_mem_schedule(struct sock *sk, int size);

bool tcp_check_oom(struct sock *sk, int shift);

extern struct proto tcp_prot;

void tcp_v4_err(struct sk_buff *skb, u32);

void tcp_shutdown(struct sock *sk, int how);

void tcp_v4_early_demux(struct sk_buff *skb);

int tcp_v4_rcv(struct sk_buff *skb);

int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);

int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);

int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
		 int flags);

void tcp_release_cb(struct sock *sk);

void tcp_wfree(struct sk_buff *skb);

void tcp_write_timer_handler(struct sock *sk);

void tcp_delack_timer_handler(struct sock *sk);

int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);

void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
			 const struct tcphdr *th, unsigned int len);

void tcp_rcv_space_adjust(struct sock *sk);

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);

void tcp_twsk_destructor(struct sock *sk);

ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
			struct pipe_inode_info *pipe, size_t len,
			unsigned int flags);

enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
					      struct sk_buff *skb,
					      const struct tcphdr *th);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
			   struct request_sock *req, bool fastopen);

int tcp_child_process(struct sock *parent, struct sock *child,
		      struct sk_buff *skb);

void tcp_enter_loss(struct sock *sk);

void tcp_clear_retrans(struct tcp_sock *tp);

void tcp_update_metrics(struct sock *sk);

void tcp_init_metrics(struct sock *sk);

bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst,
			bool paws_check, bool timestamps);

bool tcp_remember_stamp(struct sock *sk);

bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw);

void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst);

void tcp_disable_fack(struct tcp_sock *tp);

void tcp_close(struct sock *sk, long timeout);

void tcp_init_sock(struct sock *sk);

unsigned int tcp_poll(struct file *file, struct socket *sock,
		      struct poll_table_struct *wait);

int tcp_getsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, int __user *optlen);

int tcp_setsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, unsigned int optlen);

int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, int __user *optlen);


static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops,
					 const struct sock *sk, struct sk_buff *skb,
					 __u16 *mss)
{
	tcp_synq_overflow(sk);
	__NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
	return ops->cookie_init_seq(skb, mss);
}


static inline bool tcp_in_slow_start(const struct tcp_sock *tp)
{
	return tp->snd_cwnd < tp->snd_ssthresh;
}


static inline bool tcp_ca_dst_locked(const struct dst_entry *dst)
{
	return dst_metric_locked(dst, RTAX_CC_ALGO);
}


static inline void tcp_advance_highest_sack(struct sock *sk, struct sk_buff *skb)
{
	tcp_sk(sk)->highest_sack = tcp_skb_is_last(sk, skb) ? NULL :
						tcp_write_queue_next(sk, skb);
}

extern struct inet_hashinfo tcp_hashinfo;

extern struct percpu_counter tcp_orphan_count;

void tcp_time_wait(struct sock *sk, int state, int timeo);

extern struct inet_timewait_death_row tcp_death_row;

extern struct percpu_counter tcp_sockets_allocated;

void sk_forced_mem_schedule(struct sock *sk, int size);

bool tcp_check_oom(struct sock *sk, int shift);

extern struct proto tcp_prot;

void tcp_tasklet_init(void);

void tcp_v4_err(struct sk_buff *skb, u32);

void tcp_shutdown(struct sock *sk, int how);

void tcp_v4_early_demux(struct sk_buff *skb);

int tcp_v4_rcv(struct sk_buff *skb);

int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);

int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);

int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
		 int flags);

void tcp_release_cb(struct sock *sk);

void tcp_wfree(struct sk_buff *skb);

void tcp_write_timer_handler(struct sock *sk);

void tcp_delack_timer_handler(struct sock *sk);

int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);

void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
			 const struct tcphdr *th, unsigned int len);

void tcp_rcv_space_adjust(struct sock *sk);

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);

void tcp_twsk_destructor(struct sock *sk);

ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
			struct pipe_inode_info *pipe, size_t len,
			unsigned int flags);

enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
					      struct sk_buff *skb,
					      const struct tcphdr *th);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
			   struct request_sock *req, bool fastopen);

int tcp_child_process(struct sock *parent, struct sock *child,
		      struct sk_buff *skb);

void tcp_enter_loss(struct sock *sk);

void tcp_clear_retrans(struct tcp_sock *tp);

void tcp_update_metrics(struct sock *sk);

void tcp_init_metrics(struct sock *sk);

void tcp_metrics_init(void);

bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst,
			bool paws_check, bool timestamps);

bool tcp_remember_stamp(struct sock *sk);

bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw);

void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst);

void tcp_disable_fack(struct tcp_sock *tp);

void tcp_close(struct sock *sk, long timeout);

void tcp_init_sock(struct sock *sk);

unsigned int tcp_poll(struct file *file, struct socket *sock,
		      struct poll_table_struct *wait);

int tcp_getsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, int __user *optlen);

int tcp_setsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, unsigned int optlen);

int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, int __user *optlen);

int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, unsigned int optlen);

void tcp_set_keepalive(struct sock *sk, int val);

void tcp_syn_ack_timeout(const struct request_sock *req);


static inline bool inet_sk_transparent(const struct sock *sk)
{
	switch (sk->sk_state) {
	case TCP_TIME_WAIT:
		return inet_twsk(sk)->tw_transparent;
	case TCP_NEW_SYN_RECV:
		return inet_rsk(inet_reqsk(sk))->no_srccheck;
	}
	return inet_sk(sk)->transparent;
}


static inline void tcp_mib_init(struct net *net)
{
	/* See RFC 2012 */
	TCP_ADD_STATS(net, TCP_MIB_RTOALGORITHM, 1);
	TCP_ADD_STATS(net, TCP_MIB_RTOMIN, TCP_RTO_MIN*1000/HZ);
	TCP_ADD_STATS(net, TCP_MIB_RTOMAX, TCP_RTO_MAX*1000/HZ);
	TCP_ADD_STATS(net, TCP_MIB_MAXCONN, -1);
}

extern struct inet_hashinfo tcp_hashinfo;

extern struct percpu_counter tcp_orphan_count;

void tcp_time_wait(struct sock *sk, int state, int timeo);

#define TCP_RETR1	3	/*
				 * This is how many retries it does before it
				 * tries to figure out if the gateway is
				 * down. Minimal RFC value is 3; it corresponds
				 * to ~3sec-8min depending on RTO.
				 */

#define TCP_RTO_MAX	((unsigned)(120*HZ))

#define TCP_RTO_MIN	((unsigned)(HZ/5))

#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ))	/* RFC 1122 initial RTO value, now
						 * used as a fallback RTO for the
						 * initial data transmission if no
						 * valid RTT sample has been acquired,
						 * most likely due to retrans in 3WHS.
						 */

extern struct inet_timewait_death_row tcp_death_row;

extern struct percpu_counter tcp_sockets_allocated;

void sk_forced_mem_schedule(struct sock *sk, int size);

bool tcp_check_oom(struct sock *sk, int shift);

extern struct proto tcp_prot;

#define TCP_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.tcp_statistics, field)

#define __TCP_INC_STATS(net, field)	__SNMP_INC_STATS((net)->mib.tcp_statistics, field)

#define TCP_DEC_STATS(net, field)	SNMP_DEC_STATS((net)->mib.tcp_statistics, field)

#define TCP_ADD_STATS(net, field, val)	SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val)

void tcp_tasklet_init(void);

void tcp_v4_err(struct sk_buff *skb, u32);

void tcp_shutdown(struct sock *sk, int how);

void tcp_v4_early_demux(struct sk_buff *skb);

int tcp_v4_rcv(struct sk_buff *skb);

int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);

int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);

int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
		 int flags);

void tcp_release_cb(struct sock *sk);

void tcp_wfree(struct sk_buff *skb);

void tcp_write_timer_handler(struct sock *sk);

void tcp_delack_timer_handler(struct sock *sk);

int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);

void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
			 const struct tcphdr *th, unsigned int len);

void tcp_rcv_space_adjust(struct sock *sk);

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);

void tcp_twsk_destructor(struct sock *sk);

ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
			struct pipe_inode_info *pipe, size_t len,
			unsigned int flags);

enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
					      struct sk_buff *skb,
					      const struct tcphdr *th);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
			   struct request_sock *req, bool fastopen);

int tcp_child_process(struct sock *parent, struct sock *child,
		      struct sk_buff *skb);

void tcp_enter_loss(struct sock *sk);

void tcp_clear_retrans(struct tcp_sock *tp);

void tcp_update_metrics(struct sock *sk);

void tcp_init_metrics(struct sock *sk);

void tcp_metrics_init(void);


static inline void tcp_enable_fack(struct tcp_sock *tp)
{
	tp->rx_opt.sack_ok |= TCP_FACK_ENABLED;
}


static inline struct sk_buff *tcp_write_queue_prev(const struct sock *sk,
						   const struct sk_buff *skb)
{
	return skb_queue_prev(&sk->sk_write_queue, skb);
}


static inline u32 tcp_min_rtt(const struct tcp_sock *tp)
{
	return tp->rtt_min[0].rtt;
}


static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
{
	const struct inet_connection_sock *icsk = &tp->inet_conn;

	return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime,
			  tcp_time_stamp - tp->rcv_tstamp);
}


static inline void tcp_enable_early_retrans(struct tcp_sock *tp)
{
	struct net *net = sock_net((struct sock *)tp);

	tp->do_early_retrans = sysctl_tcp_early_retrans &&
		sysctl_tcp_early_retrans < 4 && !sysctl_tcp_thin_dupack &&
		net->ipv4.sysctl_tcp_reordering == 3;
}

extern struct inet_hashinfo tcp_hashinfo;

extern struct percpu_counter tcp_orphan_count;

void tcp_time_wait(struct sock *sk, int state, int timeo);

extern struct inet_timewait_death_row tcp_death_row;

extern int sysctl_tcp_reordering;

extern int sysctl_tcp_thin_dupack;

extern int sysctl_tcp_early_retrans;

extern struct percpu_counter tcp_sockets_allocated;

void sk_forced_mem_schedule(struct sock *sk, int size);

bool tcp_check_oom(struct sock *sk, int shift);

extern struct proto tcp_prot;

#define TCP_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.tcp_statistics, field)

#define __TCP_INC_STATS(net, field)	__SNMP_INC_STATS((net)->mib.tcp_statistics, field)

#define TCP_DEC_STATS(net, field)	SNMP_DEC_STATS((net)->mib.tcp_statistics, field)

#define TCP_ADD_STATS(net, field, val)	SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val)

void tcp_tasklet_init(void);

void tcp_v4_err(struct sk_buff *skb, u32);

void tcp_shutdown(struct sock *sk, int how);

void tcp_v4_early_demux(struct sk_buff *skb);

int tcp_v4_rcv(struct sk_buff *skb);

int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);

int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);

int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
		 int flags);

void tcp_release_cb(struct sock *sk);

void tcp_wfree(struct sk_buff *skb);

void tcp_write_timer_handler(struct sock *sk);

void tcp_delack_timer_handler(struct sock *sk);

int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);

void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
			 const struct tcphdr *th, unsigned int len);

void tcp_rcv_space_adjust(struct sock *sk);

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);

void tcp_twsk_destructor(struct sock *sk);

ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
			struct pipe_inode_info *pipe, size_t len,
			unsigned int flags);

enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
					      struct sk_buff *skb,
					      const struct tcphdr *th);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
			   struct request_sock *req, bool fastopen);

int tcp_child_process(struct sock *parent, struct sock *child,
		      struct sk_buff *skb);

void tcp_enter_loss(struct sock *sk);

void tcp_clear_retrans(struct tcp_sock *tp);

void tcp_update_metrics(struct sock *sk);

void tcp_init_metrics(struct sock *sk);

void tcp_metrics_init(void);

bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst,
			bool paws_check, bool timestamps);

bool tcp_remember_stamp(struct sock *sk);

bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw);

void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst);

void tcp_disable_fack(struct tcp_sock *tp);

void tcp_close(struct sock *sk, long timeout);

void tcp_init_sock(struct sock *sk);

unsigned int tcp_poll(struct file *file, struct socket *sock,
		      struct poll_table_struct *wait);

int tcp_getsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, int __user *optlen);


static inline int keepalive_time_when(const struct tcp_sock *tp)
{
	struct net *net = sock_net((struct sock *)tp);

	return tp->keepalive_time ? : net->ipv4.sysctl_tcp_keepalive_time;
}

extern struct inet_hashinfo tcp_hashinfo;

extern struct percpu_counter tcp_orphan_count;

void tcp_time_wait(struct sock *sk, int state, int timeo);

extern struct inet_timewait_death_row tcp_death_row;

extern int sysctl_tcp_timestamps;

extern int sysctl_tcp_window_scaling;

extern int sysctl_tcp_sack;

extern int sysctl_tcp_fastopen;

extern int sysctl_tcp_retrans_collapse;

extern int sysctl_tcp_stdurg;

extern int sysctl_tcp_rfc1337;

extern int sysctl_tcp_abort_on_overflow;

extern int sysctl_tcp_max_orphans;

extern int sysctl_tcp_fack;

extern int sysctl_tcp_reordering;

extern int sysctl_tcp_max_reordering;

extern int sysctl_tcp_dsack;

extern int sysctl_tcp_wmem[3];

extern int sysctl_tcp_rmem[3];

extern int sysctl_tcp_app_win;

extern int sysctl_tcp_adv_win_scale;

extern int sysctl_tcp_tw_reuse;

extern int sysctl_tcp_frto;

extern int sysctl_tcp_low_latency;

extern int sysctl_tcp_nometrics_save;

extern int sysctl_tcp_moderate_rcvbuf;

extern int sysctl_tcp_tso_win_divisor;

extern int sysctl_tcp_workaround_signed_windows;

extern int sysctl_tcp_slow_start_after_idle;

extern int sysctl_tcp_thin_linear_timeouts;

extern int sysctl_tcp_thin_dupack;

extern int sysctl_tcp_early_retrans;

extern int sysctl_tcp_limit_output_bytes;

extern int sysctl_tcp_challenge_ack_limit;

extern int sysctl_tcp_min_tso_segs;

extern int sysctl_tcp_min_rtt_wlen;

extern int sysctl_tcp_autocorking;

extern int sysctl_tcp_invalid_ratelimit;

extern int sysctl_tcp_pacing_ss_ratio;

extern int sysctl_tcp_pacing_ca_ratio;

extern struct percpu_counter tcp_sockets_allocated;

extern int tcp_memory_pressure;

void sk_forced_mem_schedule(struct sock *sk, int size);

bool tcp_check_oom(struct sock *sk, int shift);

extern struct proto tcp_prot;

#define TCP_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.tcp_statistics, field)

#define __TCP_INC_STATS(net, field)	__SNMP_INC_STATS((net)->mib.tcp_statistics, field)

#define TCP_DEC_STATS(net, field)	SNMP_DEC_STATS((net)->mib.tcp_statistics, field)

#define TCP_ADD_STATS(net, field, val)	SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val)

void tcp_v4_err(struct sk_buff *skb, u32);

void tcp_shutdown(struct sock *sk, int how);

void tcp_v4_early_demux(struct sk_buff *skb);

int tcp_v4_rcv(struct sk_buff *skb);

int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);

int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);

int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
		 int flags);

void tcp_release_cb(struct sock *sk);

void tcp_wfree(struct sk_buff *skb);

void tcp_write_timer_handler(struct sock *sk);

void tcp_delack_timer_handler(struct sock *sk);

int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);

void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
			 const struct tcphdr *th, unsigned int len);

void tcp_rcv_space_adjust(struct sock *sk);

int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);

void tcp_twsk_destructor(struct sock *sk);


static inline bool tcp_ca_needs_ecn(const struct sock *sk)
{
	const struct inet_connection_sock *icsk = inet_csk(sk);

	return icsk->icsk_ca_ops->flags & TCP_CONG_NEEDS_ECN;
}


static inline void tcp_insert_write_queue_before(struct sk_buff *new,
						  struct sk_buff *skb,
						  struct sock *sk)
{
	__skb_queue_before(&sk->sk_write_queue, skb, new);

	if (sk->sk_send_head == skb)
		sk->sk_send_head = new;
}


static inline int tcp_space(const struct sock *sk)
{
	return tcp_win_from_space(sk->sk_rcvbuf -
				  atomic_read(&sk->sk_rmem_alloc));
}


static inline bool between(__u32 seq1, __u32 seq2, __u32 seq3)
{
	return seq3 - seq2 >= seq1 - seq2;
}

#define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
					                 * for local resources.
					                 */

#define after(seq2, seq1) 	before(seq1, seq2)

bool tcp_check_oom(struct sock *sk, int shift);

struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
			   struct request_sock *req, bool fastopen);

bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst,
			bool paws_check, bool timestamps);

bool tcp_remember_stamp(struct sock *sk);

bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw);

void tcp_req_err(struct sock *sk, u32 seq, bool abort);

struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
				  struct request_sock *req,
				  struct dst_entry *dst,
				  struct request_sock *req_unhash,
				  bool *own_req);

__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mss);

__u32 cookie_init_timestamp(struct request_sock *req);

bool cookie_timestamp_decode(struct tcp_options_received *opt);

bool cookie_ecn_ok(const struct tcp_options_received *opt,
		   const struct net *net, const struct dst_entry *dst);

__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mss);

bool tcp_may_send_now(struct sock *sk);

bool tcp_schedule_loss_probe(struct sock *sk);

#define tcp_time_stamp		((__u32)(jiffies))


static inline u32 tcp_rto_min_us(struct sock *sk)
{
	return jiffies_to_usecs(tcp_rto_min(sk));
}


static INLINE BOOL ensure_capacity(const BYTE* start, const BYTE* end, size_t size, size_t base)
{
	const size_t available = (uintptr_t)end - (uintptr_t)start;
	const BOOL rc = available >= size * base;
	return rc && (start <= end);
}

Fix CVE-2020-11524: out of bounds access in interleaved

Thanks to Sunglin and HuanGMz from Knownsec 404

#define UNROLL_BODY(_exp, _count)      \
	do                                 \
	{                                  \
		size_t x;                      \
		for (x = 0; x < (_count); x++) \
		{                              \
			do                         \
				_exp while (FALSE);    \
		}                              \
	} while (FALSE)

static const BYTE g_MaskSpecialFgBg1 = 0x03;

static const BYTE g_MaskSpecialFgBg2 = 0x05;

static const BYTE g_MaskRegularRunLength = 0x1F;

static const BYTE g_MaskLiteRunLength = 0x0F;

#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 1)

#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 2)

#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 3)


BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor)
{
	BITMAP_INTERLEAVED_CONTEXT* interleaved;
	interleaved = (BITMAP_INTERLEAVED_CONTEXT*)calloc(1, sizeof(BITMAP_INTERLEAVED_CONTEXT));

	if (interleaved)
	{
		interleaved->TempSize = 64 * 64 * 4;
		interleaved->TempBuffer = _aligned_malloc(interleaved->TempSize, 16);

		if (!interleaved->TempBuffer)
		{
			free(interleaved);
			WLog_ERR(TAG, "_aligned_malloc failed!");
			return NULL;
		}

		interleaved->bts = Stream_New(NULL, interleaved->TempSize);

		if (!interleaved->bts)
		{
			_aligned_free(interleaved->TempBuffer);
			free(interleaved);
			WLog_ERR(TAG, "Stream_New failed!");
			return NULL;
		}
	}

	return interleaved;
}


BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* pSrcData,
                            UINT32 SrcSize, UINT32 nSrcWidth, UINT32 nSrcHeight, UINT32 bpp,
                            BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,
                            UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
                            const gdiPalette* palette)
{
	UINT32 scanline;
	UINT32 SrcFormat;
	UINT32 BufferSize;

	if (!interleaved || !pSrcData || !pDstData)
		return FALSE;

	switch (bpp)
	{
		case 24:
			scanline = nSrcWidth * 3;
			SrcFormat = PIXEL_FORMAT_BGR24;
			break;

		case 16:
			scanline = nSrcWidth * 2;
			SrcFormat = PIXEL_FORMAT_RGB16;
			break;

		case 15:
			scanline = nSrcWidth * 2;
			SrcFormat = PIXEL_FORMAT_RGB15;
			break;

		case 8:
			scanline = nSrcWidth;
			SrcFormat = PIXEL_FORMAT_RGB8;
			break;

		default:
			WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp);
			return FALSE;
	}

	BufferSize = scanline * nSrcHeight;

	if (BufferSize > interleaved->TempSize)
	{
		interleaved->TempBuffer = _aligned_realloc(interleaved->TempBuffer, BufferSize, 16);
		interleaved->TempSize = BufferSize;
	}

	if (!interleaved->TempBuffer)
		return FALSE;

	switch (bpp)
	{
		case 24:
			if (!RleDecompress24to24(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
			                         nSrcWidth, nSrcHeight))
				return FALSE;

			break;

		case 16:
		case 15:
			if (!RleDecompress16to16(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
			                         nSrcWidth, nSrcHeight))
				return FALSE;

			break;

		case 8:
			if (!RleDecompress8to8(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth,
			                       nSrcHeight))
				return FALSE;

			break;

		default:
			return FALSE;
	}

	return freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight,
	                          interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette,
	                          FREERDP_FLIP_VERTICAL);
}

#define TAG FREERDP_TAG("codec")

#define UNROLL_BODY(_exp, _count)      \
	do                                 \
	{                                  \
		size_t x;                      \
		for (x = 0; x < (_count); x++) \
		{                              \
			do                         \
				_exp while (FALSE);    \
		}                              \
	} while (FALSE)

#define UNROLL_MULTIPLE(_condition, _exp, _count) \
	do                                            \
	{                                             \
		while ((_condition) >= _count)            \
		{                                         \
			UNROLL_BODY(_exp, _count);            \
			(_condition) -= _count;               \
		}                                         \
	} while (FALSE)

#define UNROLL(_condition, _exp)               \
	do                                         \
	{                                          \
		UNROLL_MULTIPLE(_condition, _exp, 16); \
		UNROLL_MULTIPLE(_condition, _exp, 4);  \
		UNROLL_MULTIPLE(_condition, _exp, 1);  \
	} while (FALSE)

typedef UINT32 PIXEL;

static const BYTE g_MaskSpecialFgBg1 = 0x03;

static const BYTE g_MaskSpecialFgBg2 = 0x05;

static const BYTE g_MaskRegularRunLength = 0x1F;

static const BYTE g_MaskLiteRunLength = 0x0F;

#define RLEDECOMPRESS RleDecompress8to8

#define RLEDECOMPRESS RleDecompress16to16

#define RLEDECOMPRESS RleDecompress24to24


BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize,
                          UINT32 nWidth, UINT32 nHeight, const BYTE* pSrcData, UINT32 SrcFormat,
                          UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette,
                          UINT32 bpp)
{
	BOOL status;
	wStream* s;
	UINT32 DstFormat = 0;
	const size_t maxSize = 64 * 64 * 4;

	if (!interleaved || !pDstData || !pSrcData)
		return FALSE;

	if ((nWidth == 0) || (nHeight == 0))
		return FALSE;

	if (nWidth % 4)
	{
		WLog_ERR(TAG, "interleaved_compress: width is not a multiple of 4");
		return FALSE;
	}

	if ((nWidth > 64) || (nHeight > 64))
	{
		WLog_ERR(TAG,
		         "interleaved_compress: width (%" PRIu32 ") or height (%" PRIu32
		         ") is greater than 64",
		         nWidth, nHeight);
		return FALSE;
	}

	switch (bpp)
	{
		case 24:
			DstFormat = PIXEL_FORMAT_BGRX32;
			break;

		case 16:
			DstFormat = PIXEL_FORMAT_RGB16;
			break;

		case 15:
			DstFormat = PIXEL_FORMAT_RGB15;
			break;

		default:
			return FALSE;
	}

	if (!freerdp_image_copy(interleaved->TempBuffer, DstFormat, 0, 0, 0, nWidth, nHeight, pSrcData,
	                        SrcFormat, nSrcStep, nXSrc, nYSrc, palette, FREERDP_FLIP_NONE))
		return FALSE;

	s = Stream_New(pDstData, *pDstSize);

	if (!s)
		return FALSE;

	Stream_SetPosition(interleaved->bts, 0);

	if (freerdp_bitmap_compress(interleaved->TempBuffer, nWidth, nHeight, s, bpp, maxSize,
	                            nHeight - 1, interleaved->bts, 0) < 0)
		status = FALSE;
	else
		status = TRUE;

	Stream_SealLength(s);
	*pDstSize = (UINT32)Stream_Length(s);
	Stream_Free(s, FALSE);
	return status;
}

#define TAG FREERDP_TAG("codec")

#define UNROLL_BODY(_exp, _count)      \
	do                                 \
	{                                  \
		size_t x;                      \
		for (x = 0; x < (_count); x++) \
		{                              \
			do                         \
				_exp while (FALSE);    \
		}                              \
	} while (FALSE)

#define UNROLL_MULTIPLE(_condition, _exp, _count) \
	do                                            \
	{                                             \
		while ((_condition) >= _count)            \
		{                                         \
			UNROLL_BODY(_exp, _count);            \
			(_condition) -= _count;               \
		}                                         \
	} while (FALSE)

#define UNROLL(_condition, _exp)               \
	do                                         \
	{                                          \
		UNROLL_MULTIPLE(_condition, _exp, 16); \
		UNROLL_MULTIPLE(_condition, _exp, 4);  \
		UNROLL_MULTIPLE(_condition, _exp, 1);  \
	} while (FALSE)

typedef UINT32 PIXEL;

static const BYTE g_MaskSpecialFgBg1 = 0x03;

static const BYTE g_MaskSpecialFgBg2 = 0x05;

static const BYTE g_MaskRegularRunLength = 0x1F;

static const BYTE g_MaskLiteRunLength = 0x0F;


static INLINE UINT32 ExtractCodeId(BYTE bOrderHdr)
{
	if ((bOrderHdr & 0xC0U) != 0xC0U)
	{
		/* REGULAR orders
		 * (000x xxxx, 001x xxxx, 010x xxxx, 011x xxxx, 100x xxxx)
		 */
		return bOrderHdr >> 5;
	}
	else if ((bOrderHdr & 0xF0U) == 0xF0U)
	{
		/* MEGA and SPECIAL orders (0xF*) */
		return bOrderHdr;
	}
	else
	{
		/* LITE orders
		 * 1100 xxxx, 1101 xxxx, 1110 xxxx)
		 */
		return bOrderHdr >> 4;
	}
}

typedef UINT32 PIXEL;

static const BYTE g_MaskSpecialFgBg1 = 0x03;

static const BYTE g_MaskSpecialFgBg2 = 0x05;

static const BYTE g_MaskRegularRunLength = 0x1F;

static const BYTE g_MaskLiteRunLength = 0x0F;


static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT32* advance)
{
	UINT32 runLength;
	UINT32 ladvance;
	ladvance = 1;
	runLength = 0;

	switch (code)
	{
		case REGULAR_FGBG_IMAGE:
			runLength = (*pbOrderHdr) & g_MaskRegularRunLength;

			if (runLength == 0)
			{
				runLength = (*(pbOrderHdr + 1)) + 1;
				ladvance += 1;
			}
			else
			{
				runLength = runLength * 8;
			}

			break;

		case LITE_SET_FG_FGBG_IMAGE:
			runLength = (*pbOrderHdr) & g_MaskLiteRunLength;

			if (runLength == 0)
			{
				runLength = (*(pbOrderHdr + 1)) + 1;
				ladvance += 1;
			}
			else
			{
				runLength = runLength * 8;
			}

			break;

		case REGULAR_BG_RUN:
		case REGULAR_FG_RUN:
		case REGULAR_COLOR_RUN:
		case REGULAR_COLOR_IMAGE:
			runLength = (*pbOrderHdr) & g_MaskRegularRunLength;

			if (runLength == 0)
			{
				/* An extended (MEGA) run. */
				runLength = (*(pbOrderHdr + 1)) + 32;
				ladvance += 1;
			}

			break;

		case LITE_SET_FG_FG_RUN:
		case LITE_DITHERED_RUN:
			runLength = (*pbOrderHdr) & g_MaskLiteRunLength;

			if (runLength == 0)
			{
				/* An extended (MEGA) run. */
				runLength = (*(pbOrderHdr + 1)) + 16;
				ladvance += 1;
			}

			break;

		case MEGA_MEGA_BG_RUN:
		case MEGA_MEGA_FG_RUN:
		case MEGA_MEGA_SET_FG_RUN:
		case MEGA_MEGA_DITHERED_RUN:
		case MEGA_MEGA_COLOR_RUN:
		case MEGA_MEGA_FGBG_IMAGE:
		case MEGA_MEGA_SET_FGBG_IMAGE:
		case MEGA_MEGA_COLOR_IMAGE:
			runLength = ((UINT16)pbOrderHdr[1]) | ((UINT16)(pbOrderHdr[2] << 8));
			ladvance += 2;
			break;
	}

	*advance = ladvance;
	return runLength;
}

#define REGULAR_BG_RUN 0x00

#define MEGA_MEGA_BG_RUN 0xF0

#define REGULAR_FG_RUN 0x01

#define MEGA_MEGA_FG_RUN 0xF1

#define LITE_SET_FG_FG_RUN 0x0C

#define MEGA_MEGA_SET_FG_RUN 0xF6

#define LITE_DITHERED_RUN 0x0E

#define MEGA_MEGA_DITHERED_RUN 0xF8

#define REGULAR_COLOR_RUN 0x03

#define MEGA_MEGA_COLOR_RUN 0xF3

#define REGULAR_FGBG_IMAGE 0x02

#define MEGA_MEGA_FGBG_IMAGE 0xF2

#define LITE_SET_FG_FGBG_IMAGE 0x0D

#define MEGA_MEGA_SET_FGBG_IMAGE 0xF7

#define REGULAR_COLOR_IMAGE 0x04

#define MEGA_MEGA_COLOR_IMAGE 0xF4

typedef UINT32 PIXEL;

static const BYTE g_MaskSpecialFgBg1 = 0x03;

static const BYTE g_MaskSpecialFgBg2 = 0x05;

static const BYTE g_MaskRegularRunLength = 0x1F;

static const BYTE g_MaskLiteRunLength = 0x0F;

#define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]

#define SRCREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]


BOOL bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved)
{
	if (!interleaved)
		return FALSE;

	return TRUE;
}

#define UNROLL_BODY(_exp, _count)      \
	do                                 \
	{                                  \
		size_t x;                      \
		for (x = 0; x < (_count); x++) \
		{                              \
			do                         \
				_exp while (FALSE);    \
		}                              \
	} while (FALSE)

#define UNROLL_MULTIPLE(_condition, _exp, _count) \
	do                                            \
	{                                             \
		while ((_condition) >= _count)            \
		{                                         \
			UNROLL_BODY(_exp, _count);            \
			(_condition) -= _count;               \
		}                                         \
	} while (FALSE)

#define UNROLL(_condition, _exp)               \
	do                                         \
	{                                          \
		UNROLL_MULTIPLE(_condition, _exp, 16); \
		UNROLL_MULTIPLE(_condition, _exp, 4);  \
		UNROLL_MULTIPLE(_condition, _exp, 1);  \
	} while (FALSE)


static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
{
	*(UINT16*)_buf = _pix;
}

static const BYTE g_MaskSpecialFgBg1 = 0x03;

static const BYTE g_MaskSpecialFgBg2 = 0x05;

static const BYTE g_MaskRegularRunLength = 0x1F;

static const BYTE g_MaskLiteRunLength = 0x0F;

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_8(_buf, _pix)

#define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0]

#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0]

#define DESTNEXTPIXEL(_buf) _buf += 1

#define SRCNEXTPIXEL(_buf) _buf += 1

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_16(_buf, _pix)

#define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]

#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8)

#define SRCREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]

#define DESTNEXTPIXEL(_buf) _buf += 2

#define SRCNEXTPIXEL(_buf) _buf += 2

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_24(_buf, _pix)

#define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16)

#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16)

#define DESTNEXTPIXEL(_buf) _buf += 3

#define SRCNEXTPIXEL(_buf) _buf += 3


static INLINE void write_pixel_8(BYTE* _buf, BYTE _pix)
{
	*_buf = _pix;
}


void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved)
{
	if (!interleaved)
		return;

	_aligned_free(interleaved->TempBuffer);
	Stream_Free(interleaved->bts, TRUE);
	free(interleaved);
}

#define RLEEXTRA

#define SPECIAL_WHITE 0xFD

#define SPECIAL_BLACK 0xFE

typedef UINT32 PIXEL;

#define WHITE_PIXEL 0xFF

#define WHITE_PIXEL 0xFFFF

#define WHITE_PIXEL 0xFFFFFF

#define TAG FREERDP_TAG("codec")

#define REGULAR_BG_RUN 0x00

#define REGULAR_COLOR_RUN 0x03

#define REGULAR_COLOR_IMAGE 0x04

#define SPECIAL_FGBG_2 0xFA

#define MEGA_MEGA_BG_RUN 0xF0

#define REGULAR_FG_RUN 0x01

#define MEGA_MEGA_COLOR_RUN 0xF3

#define MEGA_MEGA_COLOR_IMAGE 0xF4

#define SPECIAL_FGBG_1 0xF9

#define MEGA_MEGA_FG_RUN 0xF1

#define LITE_DITHERED_RUN 0x0E

#define REGULAR_FGBG_IMAGE 0x02

#define BLACK_PIXEL 0x000000

#define MEGA_MEGA_SET_FG_RUN 0xF6

#define MEGA_MEGA_DITHERED_RUN 0xF8

#define MEGA_MEGA_FGBG_IMAGE 0xF2

#define DESTNEXTPIXEL(_buf) _buf += 1

#define SRCNEXTPIXEL(_buf) _buf += 1

#define DESTNEXTPIXEL(_buf) _buf += 2

#define SRCNEXTPIXEL(_buf) _buf += 2

#define DESTNEXTPIXEL(_buf) _buf += 3

#define SRCNEXTPIXEL(_buf) _buf += 3

#define LITE_SET_FG_FG_RUN 0x0C

#define MEGA_MEGA_SET_FGBG_IMAGE 0xF7

#define WRITEFGBGIMAGE WriteFgBgImage8to8

#define RLEDECOMPRESS RleDecompress8to8

#define LITE_SET_FG_FGBG_IMAGE 0x0D

static const BYTE g_MaskRegularRunLength = 0x1F;

static const BYTE g_MaskLiteRunLength = 0x0F;

#define WRITEFGBGIMAGE WriteFgBgImage16to16

#define RLEDECOMPRESS RleDecompress16to16

#define WRITEFGBGIMAGE WriteFgBgImage24to24

#define RLEDECOMPRESS RleDecompress24to24

static const BYTE g_MaskSpecialFgBg1 = 0x03;

static const BYTE g_MaskSpecialFgBg2 = 0x05;

#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage8to8

#define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0]

#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0]

#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage16to16

#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage24to24

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_8(_buf, _pix)

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_16(_buf, _pix)

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_24(_buf, _pix)

#define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]

#define SRCREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]

#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 1)

#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 2)


static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix)
{
	(_buf)[0] = (BYTE)(_pix);
	(_buf)[1] = (BYTE)((_pix) >> 8);
	(_buf)[2] = (BYTE)((_pix) >> 16);
}

typedef UINT32 PIXEL;

static const BYTE g_MaskSpecialFgBg1 = 0x03;

static const BYTE g_MaskSpecialFgBg2 = 0x05;

static const BYTE g_MaskRegularRunLength = 0x1F;

static const BYTE g_MaskLiteRunLength = 0x0F;

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_8(_buf, _pix)

#define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0]

#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0]

#define DESTNEXTPIXEL(_buf) _buf += 1

#define SRCNEXTPIXEL(_buf) _buf += 1

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_16(_buf, _pix)

#define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]

#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8)

#define SRCREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]

#define DESTNEXTPIXEL(_buf) _buf += 2

#define SRCNEXTPIXEL(_buf) _buf += 2

#define DESTWRITEPIXEL(_buf, _pix) write_pixel_24(_buf, _pix)

#define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16)

#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16)

#define DESTNEXTPIXEL(_buf) _buf += 3

#define SRCNEXTPIXEL(_buf) _buf += 3


parselet(struct scanner *s, struct evalstring **val)
{
	scanchar(s, '=');
	*val = scanstring(s, false);
	scannewline(s);
}

parse: Check for non-empty command/rspfile/rspfile_content

This matches ninja behavior and prevents the possibility of a rule
with an empty (NULL) command string.

Fixes #68.

struct parseoptions parseopts;

static struct node **deftarg;


parseedge(struct scanner *s, struct environment *env)
{
	struct edge *e;
	struct evalstring *out, *in, *str, **end;
	char *name;
	struct string *val;
	struct node *n;
	size_t i;
	int p;

	e = mkedge(env);

	for (out = NULL, end = &out; (str = scanstring(s, true)); ++e->nout)
		pushstr(&end, str);
	e->outimpidx = e->nout;
	if (scanpipe(s, 1)) {
		for (; (str = scanstring(s, true)); ++e->nout)
			pushstr(&end, str);
	}
	if (e->nout == 0)
		scanerror(s, "expected output path");
	scanchar(s, ':');
	name = scanname(s);
	e->rule = envrule(env, name);
	if (!e->rule)
		fatal("undefined rule '%s'", name);
	free(name);
	for (in = NULL, end = ∈ (str = scanstring(s, true)); ++e->nin)
		pushstr(&end, str);
	e->inimpidx = e->nin;
	p = scanpipe(s, 1 | 2);
	if (p == 1) {
		for (; (str = scanstring(s, true)); ++e->nin)
			pushstr(&end, str);
		p = scanpipe(s, 2);
	}
	e->inorderidx = e->nin;
	if (p == 2) {
		for (; (str = scanstring(s, true)); ++e->nin)
			pushstr(&end, str);
	}
	scannewline(s);
	while (scanindent(s)) {
		name = scanname(s);
		parselet(s, &str);
		val = enveval(env, str);
		envaddvar(e->env, name, val);
	}

	e->out = xreallocarray(NULL, e->nout, sizeof(e->out[0]));
	for (i = 0; i < e->nout; out = str) {
		str = out->next;
		val = enveval(e->env, out);
		canonpath(val);
		n = mknode(val);
		if (n->gen) {
			if (!parseopts.dupbuildwarn)
				fatal("multiple rules generate '%s'", n->path->s);
			warn("multiple rules generate '%s'", n->path->s);
			--e->nout;
			if (i < e->outimpidx)
				--e->outimpidx;
		} else {
			n->gen = e;
			e->out[i] = n;
			++i;
		}
	}

	e->in = xreallocarray(NULL, e->nin, sizeof(e->in[0]));
	for (i = 0; i < e->nin; in = str, ++i) {
		str = in->next;
		val = enveval(e->env, in);
		canonpath(val);
		n = mknode(val);
		e->in[i] = n;
		nodeuse(n, e);
	}

	val = edgevar(e, "pool", true);
	if (val)
		e->pool = poolget(val->s);
}

struct parseoptions parseopts;

static struct node **deftarg;

static size_t ndeftarg;


parseinit(void)
{
	free(deftarg);
	deftarg = NULL;
	ndeftarg = 0;
}

static struct node **deftarg;

static size_t ndeftarg;


parseinclude(struct scanner *s, struct environment *env, bool newscope)
{
	struct evalstring *str;
	struct string *path;

	str = scanstring(s, true);
	if (!str)
		scanerror(s, "expected include path");
	scannewline(s);
	path = enveval(env, str);

	if (newscope)
		env = mkenv(env);
	parse(path->s, env);
	free(path);
}


checkversion(const char *ver)
{
	int major, minor = 0;

	if (sscanf(ver, "%d.%d", &major, &minor) < 1)
		fatal("invalid ninja_required_version");
	if (major > ninjamajor || (major == ninjamajor && minor > ninjaminor))
		fatal("ninja_required_version %s is newer than %d.%d", ver, ninjamajor, ninjaminor);
}

struct parseoptions parseopts;

static size_t ndeftarg;

static struct node **deftarg;


parse(const char *name, struct environment *env)
{
	struct scanner s;
	char *var;
	struct string *val;
	struct evalstring *str;

	scaninit(&s, name);
	for (;;) {
		switch (scankeyword(&s, &var)) {
		case RULE:
			parserule(&s, env);
			break;
		case BUILD:
			parseedge(&s, env);
			break;
		case INCLUDE:
			parseinclude(&s, env, false);
			break;
		case SUBNINJA:
			parseinclude(&s, env, true);
			break;
		case DEFAULT:
			parsedefault(&s, env);
			break;
		case POOL:
			parsepool(&s, env);
			break;
		case VARIABLE:
			parselet(&s, &str);
			val = enveval(env, str);
			if (strcmp(var, "ninja_required_version") == 0)
				checkversion(val->s);
			envaddvar(env, var, val);
			break;
		case EOF:
			scanclose(&s);
			return;
		}
	}
}


defaultnodes(void fn(struct node *))
{
	struct edge *e;
	struct node *n;
	size_t i;

	if (ndeftarg > 0) {
		for (i = 0; i < ndeftarg; ++i)
			fn(deftarg[i]);
	} else {
		/* by default build all nodes which are not used by any edges */
		for (e = alledges; e; e = e->allnext) {
			for (i = 0; i < e->nout; ++i) {
				n = e->out[i];
				if (n->nuse == 0)
					fn(n);
			}
		}
	}
}


parserule(struct scanner *s, struct environment *env)
{
	struct rule *r;
	char *var;
	struct evalstring *val;
	bool hascommand = false, hasrspfile = false, hasrspcontent = false;

	r = mkrule(scanname(s));
	scannewline(s);
	while (scanindent(s)) {
		var = scanname(s);
		parselet(s, &val);
		ruleaddvar(r, var, val);
		if (!val)
			continue;
		if (strcmp(var, "command") == 0)
			hascommand = true;
		else if (strcmp(var, "rspfile") == 0)
			hasrspfile = true;
		else if (strcmp(var, "rspfile_content") == 0)
			hasrspcontent = true;
	}
	if (!hascommand)
		fatal("rule '%s' has no command", r->name);
	if (hasrspfile != hasrspcontent)
		fatal("rule '%s' has rspfile and no rspfile_content or vice versa", r->name);
	envaddrule(env, r);
}


pushstr(struct evalstring ***end, struct evalstring *str)
{
	str->next = NULL;
	**end = str;
	*end = &str->next;
}


parsepool(struct scanner *s, struct environment *env)
{
	struct pool *p;
	struct evalstring *val;
	struct string *str;
	char *var, *end;

	p = mkpool(scanname(s));
	scannewline(s);
	while (scanindent(s)) {
		var = scanname(s);
		parselet(s, &val);
		if (strcmp(var, "depth") == 0) {
			str = enveval(env, val);
			p->maxjobs = strtol(str->s, &end, 10);
			if (*end)
				fatal("invalid pool depth '%s'", str->s);
			free(str);
		} else {
			fatal("unexpected pool variable '%s'", var);
		}
	}
	if (!p->maxjobs)
		fatal("pool '%s' has no depth", p->name);
}


parsedefault(struct scanner *s, struct environment *env)
{
	struct evalstring *targ, *str, **end;
	struct string *path;
	struct node *n;
	size_t ntarg;

	for (targ = NULL, ntarg = 0, end = &targ; (str = scanstring(s, true)); ++ntarg)
		pushstr(&end, str);
	deftarg = xreallocarray(deftarg, ndeftarg + ntarg, sizeof(*deftarg));
	for (; targ; targ = str) {
		str = targ->next;
		path = enveval(env, targ);
		canonpath(path);
		n = nodeget(path->s, path->n);
		if (!n)
			fatal("unknown target '%s'", path->s);
		free(path);
		deftarg[ndeftarg++] = n;
	}
	scannewline(s);
}


W(set_send_to_gpu) {
    send_to_gpu = PyObject_IsTrue(args) ? true : false;
    Py_RETURN_NONE;
}

Graphics protocol: Dont return filename in the error message when opening file fails, since filenames can contain control characters

Fixes #3128

static bool send_to_gpu = true;

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


grman_alloc() {
    GraphicsManager *self = (GraphicsManager *)GraphicsManager_Type.tp_alloc(&GraphicsManager_Type, 0);
    self->images_capacity = self->capacity = 64;
    self->images = calloc(self->images_capacity, sizeof(Image));
    self->render_data = calloc(self->capacity, sizeof(ImageRenderData));
    if (self->images == NULL || self->render_data == NULL) {
        PyErr_NoMemory();
        Py_CLEAR(self); return NULL;
    }
    return self;
}

PyTypeObject GraphicsManager_Type;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


set_add_response(const char *code, const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    size_t sz = sizeof(add_response)/sizeof(add_response[0]);
    int num = snprintf(add_response, sz, "%s:", code);
    vsnprintf(add_response + num, sz - num, fmt, args);
    va_end(args);
    has_add_respose = true;
}

static bool send_to_gpu = true;

static char add_response[512] = {0};

static bool has_add_respose = false;

#define ABRT(code, ...) { set_add_response(#code, __VA_ARGS__); goto err; }

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};


dealloc(GraphicsManager* self) {
    size_t i;
    if (self->images) {
        for (i = 0; i < self->image_count; i++) free_image(self, self->images + i);
        free(self->images);
    }
    free(self->render_data);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};


inflate_png(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz) {
    png_read_data d = {.err_handler=png_error_handler};
    inflate_png_inner(&d, buf, bufsz);
    if (d.ok) {
        free_load_data(&img->load_data);
        img->load_data.buf = d.decompressed;
        img->load_data.buf_capacity = d.sz;
        img->load_data.buf_used = d.sz;
        img->load_data.data_sz = d.sz;
        img->width = d.width; img->height = d.height;
    }
    else free(d.decompressed);
    free(d.row_pointers);
    return d.ok;
}

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};


create_add_response(GraphicsManager UNUSED *self, bool data_loaded, uint32_t iid) {
    static char rbuf[sizeof(add_response)/sizeof(add_response[0]) + 64];
    if (iid) {
        if (!has_add_respose) {
            if (!data_loaded) return NULL;
            snprintf(add_response, 10, "OK");
        }
        snprintf(rbuf, sizeof(rbuf)/sizeof(rbuf[0]) - 1, "Gi=%u;%s", iid, add_response);
        return rbuf;
    }
    return NULL;
}

static bool send_to_gpu = true;

static id_type internal_id_counter = 1;

static char add_response[512] = {0};

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


init_graphics(PyObject *module) {
    if (PyType_Ready(&GraphicsManager_Type) < 0) return false;
    if (PyModule_AddObject(module, "GraphicsManager", (PyObject *)&GraphicsManager_Type) != 0) return false;
    if (PyModule_AddFunctions(module, module_methods) != 0) return false;
    Py_INCREF(&GraphicsManager_Type);
    return true;
}

PyTypeObject GraphicsManager_Type;

static bool send_to_gpu = true;

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


free_refs_data(Image *img) {
    free(img->refs); img->refs = NULL;
    img->refcnt = 0; img->refcap = 0;
}

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


oldest_last(const void* a, const void *b) {
    monotonic_t ans = ((Image*)(b))->atime - ((Image*)(a))->atime;
    return ans < 0 ? -1 : (ans == 0 ? 0 : 1);
}

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;


modify_refs(GraphicsManager *self, const void* data, bool free_images, bool (*filter_func)(ImageRef*, Image*, const void*, CellPixelSize), CellPixelSize cell) {
    for (size_t i = self->image_count; i-- > 0;) {
        Image *img = self->images + i;
        for (size_t j = img->refcnt; j-- > 0;) {
            if (filter_func(img->refs + j, img, data, cell)) remove_i_from_array(img->refs, j, img->refcnt);
        }
        if (img->refcnt == 0 && (free_images || img->client_id == 0)) remove_image(self, i);
    }
}

static bool send_to_gpu = true;

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};


ref_within_region(const ImageRef *ref, index_type margin_top, index_type margin_bottom) {
    return ref->start_row >= (int32_t)margin_top && ref->start_row + ref->effective_num_rows <= margin_bottom;
}


W(image_for_client_id) {
    unsigned long id = PyLong_AsUnsignedLong(args);
    bool existing = false;
    Image *img = find_or_create_image(self, id, &existing);
    if (!existing) { Py_RETURN_NONE; }
    return image_as_dict(img);
}

static bool send_to_gpu = true;

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};


filter_refs(GraphicsManager *self, const void* data, bool free_images, bool (*filter_func)(const ImageRef*, Image*, const void*, CellPixelSize), CellPixelSize cell) {
    for (size_t i = self->image_count; i-- > 0;) {
        Image *img = self->images + i;
        for (size_t j = img->refcnt; j-- > 0;) {
            ImageRef *ref = img->refs + j;
            if (filter_func(ref, img, data, cell)) {
                remove_i_from_array(img->refs, j, img->refcnt);
                self->layers_dirty = true;
            }
        }
        if (img->refcnt == 0 && (free_images || img->client_id == 0)) remove_image(self, i);
    }
}


trim_predicate(Image *img) {
    return !img->data_loaded || !img->refcnt;
}


free_image(GraphicsManager *self, Image *img) {
    if (img->texture_id) free_texture(&img->texture_id);
    free_refs_data(img);
    free_load_data(&(img->load_data));
    self->used_storage -= img->used_storage;
}


set_vertex_data(ImageRenderData *rd, const ImageRef *ref, const ImageRect *dest_rect) {
#define R(n, a, b) rd->vertices[n*4] = ref->src_rect.a; rd->vertices[n*4 + 1] = ref->src_rect.b; rd->vertices[n*4 + 2] = dest_rect->a; rd->vertices[n*4 + 3] = dest_rect->b;
        R(0, right, top); R(1, right, bottom); R(2, left, bottom); R(3, left, top);
#undef R
}

#define STORAGE_LIMIT (320u * (1024u * 1024u))

#define REPORT_ERROR(...) { log_error(__VA_ARGS__); }

#define ABRT(code, ...) { set_add_response(#code, __VA_ARGS__); goto err; }

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

#define M(x, va) {#x, (PyCFunction)py##x, va, ""}


remove_images(GraphicsManager *self, bool(*predicate)(Image*), id_type skip_image_internal_id) {
    for (size_t i = self->image_count; i-- > 0;) {
        Image *img = self->images + i;
        if (img->internal_id != skip_image_internal_id && predicate(img)) {
            remove_image(self, i);
        }
    }
}

static bool send_to_gpu = true;

static id_type internal_id_counter = 1;

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};


grman_clear(GraphicsManager *self, bool all, CellPixelSize cell) {
    filter_refs(self, NULL, true, all ? clear_all_filter_func : clear_filter_func, cell);
}

static bool send_to_gpu = true;

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


grman_resize(GraphicsManager *self, index_type UNUSED old_lines, index_type UNUSED lines, index_type UNUSED old_columns, index_type UNUSED columns) {
    self->layers_dirty = true;
}

static bool send_to_gpu = true;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};


remove_image(GraphicsManager *self, size_t idx) {
    free_image(self, self->images + idx);
    remove_i_from_array(self->images, idx, self->image_count);
    self->layers_dirty = true;
}


update_src_rect(ImageRef *ref, Image *img) {
    // The src rect in OpenGL co-ords [0, 1] with origin at top-left corner of image
    ref->src_rect.left = (float)ref->src_x / (float)img->width;
    ref->src_rect.right = (float)(ref->src_x + ref->src_width) / (float)img->width;
    ref->src_rect.top = (float)ref->src_y / (float)img->height;
    ref->src_rect.bottom = (float)(ref->src_y + ref->src_height) / (float)img->height;
}

PyTypeObject GraphicsManager_Type;

static bool send_to_gpu = true;

static bool has_add_respose = false;

static id_type internal_id_counter = 1;

#define REPORT_ERROR(...) { log_error(__VA_ARGS__); }

static char add_response[512] = {0};

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define ABRT(code, ...) { set_add_response(#code, __VA_ARGS__); goto err; }

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

#define STORAGE_LIMIT (320u * (1024u * 1024u))

#define M(x, va) {#x, (PyCFunction)py##x, va, ""}

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};


handle_delete_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c, bool *is_dirty, CellPixelSize cell) {
    static GraphicsCommand d;
    switch (g->delete_action) {
#define I(u, data, func) filter_refs(self, data, g->delete_action == u, func, cell); *is_dirty = true; break
#define D(l, u, data, func) case l: case u: I(u, data, func)
#define G(l, u, func) D(l, u, g, func)
        case 0:
        D('a', 'A', NULL, clear_filter_func);
        D('i', 'I', &g->id, id_filter_func);
        G('p', 'P', point_filter_func);
        G('q', 'Q', point3d_filter_func);
        G('x', 'X', x_filter_func);
        G('y', 'Y', y_filter_func);
        G('z', 'Z', z_filter_func);
        case 'c':
        case 'C':
            d.x_offset = c->x + 1; d.y_offset = c->y + 1;
            I('C', &d, point_filter_func);
        default:
            REPORT_ERROR("Unknown graphics command delete action: %c", g->delete_action);
            break;
#undef G
#undef D
#undef I
    }
    if (!self->image_count && self->count) self->count = 0;
}

#define STORAGE_LIMIT (320u * (1024u * 1024u))

#define REPORT_ERROR(...) { log_error(__VA_ARGS__); }

static bool send_to_gpu = true;

static id_type internal_id_counter = 1;

static char add_response[512] = {0};

static bool has_add_respose = false;

#define ABRT(code, ...) { set_add_response(#code, __VA_ARGS__); goto err; }

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

#define M(x, va) {#x, (PyCFunction)py##x, va, ""}

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


scroll_filter_func(ImageRef *ref, Image UNUSED *img, const void *data, CellPixelSize cell UNUSED) {
    ScrollData *d = (ScrollData*)data;
    ref->start_row += d->amt;
    return ref->start_row + (int32_t)ref->effective_num_rows <= d->limit;
}

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;


point_filter_func(const ImageRef *ref, Image *img, const void *data, CellPixelSize cell) {
    return x_filter_func(ref, img, data, cell) && y_filter_func(ref, img, data, cell);
}


grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload, Cursor *c, bool *is_dirty, CellPixelSize cell) {
    const char *ret = NULL;

    switch(g->action) {
        case 0:
        case 't':
        case 'T':
        case 'q': {
            uint32_t iid = g->id, q_iid = iid;
            if (g->action == 'q') { iid = 0; if (!q_iid) { REPORT_ERROR("Query graphics command without image id"); break; } }
            Image *image = handle_add_command(self, g, payload, is_dirty, iid);
            ret = create_add_response(self, image != NULL, g->action == 'q' ? q_iid: self->last_init_graphics_command.id);
            if (self->last_init_graphics_command.action == 'T' && image && image->data_loaded) handle_put_command(self, &self->last_init_graphics_command, c, is_dirty, image, cell);
            id_type added_image_id = image ? image->internal_id : 0;
            if (g->action == 'q') remove_images(self, add_trim_predicate, 0);
            if (self->used_storage > STORAGE_LIMIT) apply_storage_quota(self, STORAGE_LIMIT, added_image_id);
            break;
        }
        case 'p':
            if (!g->id) {
                REPORT_ERROR("Put graphics command without image id");
                break;
            }
            handle_put_command(self, g, c, is_dirty, NULL, cell);
            ret = create_add_response(self, true, g->id);
            break;
        case 'd':
            handle_delete_command(self, g, c, is_dirty, cell);
            break;
        default:
            REPORT_ERROR("Unknown graphics command action: %c", g->action);
            break;
    }
    return ret;
}

#define STORAGE_LIMIT (320u * (1024u * 1024u))

#define REPORT_ERROR(...) { log_error(__VA_ARGS__); }

static bool send_to_gpu = true;

static id_type internal_id_counter = 1;

static char add_response[512] = {0};

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


gpu_data_for_centered_image(ImageRenderData *ans, unsigned int screen_width_px, unsigned int screen_height_px, unsigned int width, unsigned int height) {
    static const ImageRef source_rect = { .src_rect = { .left=0, .top=0, .bottom=1, .right=1 }};
    const ImageRef *ref = &source_rect;
    float width_frac = 2 * MIN(1, width / (float)screen_width_px), height_frac = 2 * MIN(1, height / (float)screen_height_px);
    float hmargin = (2 - width_frac) / 2;
    float vmargin = (2 - height_frac) / 2;
    const ImageRect r = { .left = -1 + hmargin, .right = -1 + hmargin + width_frac, .top = 1 - vmargin, .bottom = 1 - vmargin - height_frac };
    set_vertex_data(ans, ref, &r);
}

static bool send_to_gpu = true;

static id_type internal_id_counter = 1;

static char add_response[512] = {0};

static bool has_add_respose = false;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


W(shm_unlink) {
    char *name;
    PA("s", &name);
    int ret = shm_unlink(name);
    if (ret == -1) { PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); return NULL; }
    Py_RETURN_NONE;
}

static char add_response[512] = {0};

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


new(PyTypeObject UNUSED *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
    PyObject *ans = (PyObject*)grman_alloc();
    if (ans == NULL) PyErr_NoMemory();
    return ans;
}

PyTypeObject GraphicsManager_Type;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


cmp_by_zindex_and_image(const void *a_, const void *b_) {
    const ImageRenderData *a = (const ImageRenderData*)a_, *b = (const ImageRenderData*)b_;
    int ans = a->z_index - b->z_index;
    if (ans == 0) ans = a->image_id - b->image_id;
    return ans;
}


update_dest_rect(ImageRef *ref, uint32_t num_cols, uint32_t num_rows, CellPixelSize cell) {
    uint32_t t;
    if (num_cols == 0) {
        t = ref->src_width + ref->cell_x_offset;
        num_cols = t / cell.width;
        if (t > num_cols * cell.width) num_cols += 1;
    }
    if (num_rows == 0) {
        t = ref->src_height + ref->cell_y_offset;
        num_rows = t / cell.height;
        if (t > num_rows * cell.height) num_rows += 1;
    }
    ref->effective_num_rows = num_rows;
    ref->effective_num_cols = num_cols;
}


z_filter_func(const ImageRef *ref, Image UNUSED *img, const void *data, CellPixelSize cell UNUSED) {
    const GraphicsCommand *g = data;
    return ref->z_index == g->z_index;
}


ref_outside_region(const ImageRef *ref, index_type margin_top, index_type margin_bottom) {
    return ref->start_row + ref->effective_num_rows <= margin_top || ref->start_row > (int32_t)margin_bottom;
}


image_as_dict(Image *img) {
#define U(x) #x, img->x
    return Py_BuildValue("{sI sI sI sI sK sI sO sO sN}",
        U(texture_id), U(client_id), U(width), U(height), U(internal_id), U(refcnt),
        "data_loaded", img->data_loaded ? Py_True : Py_False,
        "is_4byte_aligned", img->load_data.is_4byte_aligned ? Py_True : Py_False,
        "data", Py_BuildValue("y#", img->load_data.data, img->load_data.data_sz)
    );
#undef U

}


grman_scroll_images(GraphicsManager *self, const ScrollData *data, CellPixelSize cell) {
    if (self->image_count) {
        self->layers_dirty = true;
        modify_refs(self, data, true, data->has_margins ? scroll_filter_margins_func : scroll_filter_func, cell);
    }
}


y_filter_func(const ImageRef *ref, Image UNUSED *img, const void *data, CellPixelSize cell UNUSED) {
    const GraphicsCommand *g = data;
    return ref->start_row <= (int32_t)g->y_offset - 1 && ((int32_t)(g->y_offset - 1 < ref->start_row + ref->effective_num_rows));
}


inflate_zlib(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz) {
    bool ok = false;
    z_stream z;
    uint8_t *decompressed = malloc(img->load_data.data_sz);
    if (decompressed == NULL) fatal("Out of memory allocating decompression buffer");
    z.zalloc = Z_NULL;
    z.zfree = Z_NULL;
    z.opaque = Z_NULL;
    z.avail_in = bufsz;
    z.next_in = (Bytef*)buf;
    z.avail_out = img->load_data.data_sz;
    z.next_out = decompressed;
    int ret;
    if ((ret = inflateInit(&z)) != Z_OK) ABRT(ENOMEM, "Failed to initialize inflate with error: %s", zlib_strerror(ret));
    if ((ret = inflate(&z, Z_FINISH)) != Z_STREAM_END) ABRT(EINVAL, "Failed to inflate image data with error: %s", zlib_strerror(ret));
    if (z.avail_out) ABRT(EINVAL, "Image data size post inflation does not match expected size");
    free_load_data(&img->load_data);
    img->load_data.buf_capacity = img->load_data.data_sz;
    img->load_data.buf = decompressed;
    img->load_data.buf_used = img->load_data.data_sz;
    ok = true;
err:
    inflateEnd(&z);
    if (!ok) free(decompressed);
    return ok;
}

static bool send_to_gpu = true;

static bool has_add_respose = false;

#define ABRT(code, ...) { set_add_response(#code, __VA_ARGS__); goto err; }

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMethodDef methods[] = {
    M(image_for_client_id, METH_O),
    M(update_layers, METH_VARARGS),
    {NULL}  /* Sentinel */
};

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};

static PyMethodDef module_methods[] = {
    M(shm_write, METH_VARARGS),
    M(shm_unlink, METH_VARARGS),
    M(set_send_to_gpu, METH_O),
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload, bool *is_dirty, uint32_t iid) {
#define ABRT(code, ...) { set_add_response(#code, __VA_ARGS__); self->loading_image = 0; if (img) img->data_loaded = false; return NULL; }
#define MAX_DATA_SZ (4u * 100000000u)
    has_add_respose = false;
    bool existing, init_img = true;
    Image *img = NULL;
    unsigned char tt = g->transmission_type ? g->transmission_type : 'd';
    enum FORMATS { RGB=24, RGBA=32, PNG=100 };
    uint32_t fmt = g->format ? g->format : RGBA;
    if (tt == 'd' && self->loading_image) init_img = false;
    if (init_img) {
        self->last_init_graphics_command = *g;
        self->last_init_graphics_command.id = iid;
        self->loading_image = 0;
        if (g->data_width > 10000 || g->data_height > 10000) ABRT(EINVAL, "Image too large");
        remove_images(self, add_trim_predicate, 0);
        img = find_or_create_image(self, iid, &existing);
        if (existing) {
            free_load_data(&img->load_data);
            img->data_loaded = false;
            free_refs_data(img);
            *is_dirty = true;
            self->layers_dirty = true;
        } else {
            img->internal_id = internal_id_counter++;
            img->client_id = iid;
        }
        img->atime = monotonic(); img->used_storage = 0;
        img->width = g->data_width; img->height = g->data_height;
        switch(fmt) {
            case PNG:
                if (g->data_sz > MAX_DATA_SZ) ABRT(EINVAL, "PNG data size too large");
                img->load_data.is_4byte_aligned = true;
                img->load_data.is_opaque = false;
                img->load_data.data_sz = g->data_sz ? g->data_sz : 1024 * 100;
                break;
            case RGB:
            case RGBA:
                img->load_data.data_sz = (size_t)g->data_width * g->data_height * (fmt / 8);
                if (!img->load_data.data_sz) ABRT(EINVAL, "Zero width/height not allowed");
                img->load_data.is_4byte_aligned = fmt == RGBA || (img->width % 4 == 0);
                img->load_data.is_opaque = fmt == RGB;
                break;
            default:
                ABRT(EINVAL, "Unknown image format: %u", fmt);
        }
        if (tt == 'd') {
            if (g->more) self->loading_image = img->internal_id;
            img->load_data.buf_capacity = img->load_data.data_sz + (g->compressed ? 1024 : 10);  // compression header
            img->load_data.buf = malloc(img->load_data.buf_capacity);
            img->load_data.buf_used = 0;
            if (img->load_data.buf == NULL) {
                ABRT(ENOMEM, "Out of memory");
                img->load_data.buf_capacity = 0; img->load_data.buf_used = 0;
            }
        }
    } else {
        self->last_init_graphics_command.more = g->more;
        self->last_init_graphics_command.payload_sz = g->payload_sz;
        g = &self->last_init_graphics_command;
        tt = g->transmission_type ? g->transmission_type : 'd';
        fmt = g->format ? g->format : RGBA;
        img = img_by_internal_id(self, self->loading_image);
        if (img == NULL) {
            self->loading_image = 0;
            ABRT(EILSEQ, "More payload loading refers to non-existent image");
        }
    }
    int fd;
    static char fname[2056] = {0};
    switch(tt) {
        case 'd':  // direct
            if (img->load_data.buf_capacity - img->load_data.buf_used < g->payload_sz) {
                if (img->load_data.buf_used + g->payload_sz > MAX_DATA_SZ || fmt != PNG) ABRT(EFBIG, "Too much data");
                img->load_data.buf_capacity = MIN(2 * img->load_data.buf_capacity, MAX_DATA_SZ);
                img->load_data.buf = realloc(img->load_data.buf, img->load_data.buf_capacity);
                if (img->load_data.buf == NULL) {
                    ABRT(ENOMEM, "Out of memory");
                    img->load_data.buf_capacity = 0; img->load_data.buf_used = 0;
                }
            }
            memcpy(img->load_data.buf + img->load_data.buf_used, payload, g->payload_sz);
            img->load_data.buf_used += g->payload_sz;
            if (!g->more) { img->data_loaded = true; self->loading_image = 0; }
            break;
        case 'f': // file
        case 't': // temporary file
        case 's': // POSIX shared memory
            if (g->payload_sz > 2048) ABRT(EINVAL, "Filename too long");
            snprintf(fname, sizeof(fname)/sizeof(fname[0]), "%.*s", (int)g->payload_sz, payload);
            if (tt == 's') fd = shm_open(fname, O_RDONLY, 0);
            else fd = open(fname, O_CLOEXEC | O_RDONLY);
            if (fd == -1) ABRT(EBADF, "Failed to open file for graphics transmission with error: [%d] %s", errno, strerror(errno));
            img->data_loaded = mmap_img_file(self, img, fd, g->data_sz, g->data_offset);
            safe_close(fd, __FILE__, __LINE__);
            if (tt == 't') {
                if (global_state.boss) { call_boss(safe_delete_temp_file, "s", fname); }
                else unlink(fname);
            }
            else if (tt == 's') shm_unlink(fname);
            break;
        default:
            ABRT(EINVAL, "Unknown transmission type: %c", g->transmission_type);
    }
    if (!img->data_loaded) return NULL;
    self->loading_image = 0;
    bool needs_processing = g->compressed || fmt == PNG;
    if (needs_processing) {
        uint8_t *buf; size_t bufsz;
#define IB { if (img->load_data.buf) { buf = img->load_data.buf; bufsz = img->load_data.buf_used; } else { buf = img->load_data.mapped_file; bufsz = img->load_data.mapped_file_sz; } }
        switch(g->compressed) {
            case 'z':
                IB;
                if (!inflate_zlib(self, img, buf, bufsz)) {
                    img->data_loaded = false; return NULL;
                }
                break;
            case 0:
                break;
            default:
                ABRT(EINVAL, "Unknown image compression: %c", g->compressed);
        }
        switch(fmt) {
            case PNG:
                IB;
                if (!inflate_png(self, img, buf, bufsz)) {
                    img->data_loaded = false; return NULL;
                }
                break;
            default: break;
        }
#undef IB
        img->load_data.data = img->load_data.buf;
        if (img->load_data.buf_used < img->load_data.data_sz) {
            ABRT(ENODATA, "Insufficient image data: %zu < %zu", img->load_data.buf_used, img->load_data.data_sz);
        }
        if (img->load_data.mapped_file) {
            munmap(img->load_data.mapped_file, img->load_data.mapped_file_sz);
            img->load_data.mapped_file = NULL; img->load_data.mapped_file_sz = 0;
        }
    } else {
        if (tt == 'd') {
            if (img->load_data.buf_used < img->load_data.data_sz) {
                ABRT(ENODATA, "Insufficient image data: %zu < %zu",  img->load_data.buf_used, img->load_data.data_sz);
            } else img->load_data.data = img->load_data.buf;
        } else {
            if (img->load_data.mapped_file_sz < img->load_data.data_sz) {
                ABRT(ENODATA, "Insufficient image data: %zu < %zu",  img->load_data.mapped_file_sz, img->load_data.data_sz);
            } else img->load_data.data = img->load_data.mapped_file;
        }
    }
    size_t required_sz = (size_t)(img->load_data.is_opaque ? 3 : 4) * img->width * img->height;
    if (img->load_data.data_sz != required_sz) ABRT(EINVAL, "Image dimensions: %ux%u do not match data size: %zu, expected size: %zu", img->width, img->height, img->load_data.data_sz, required_sz);
    if (LIKELY(img->data_loaded && send_to_gpu)) {
        send_image_to_gpu(&img->texture_id, img->load_data.data, img->width, img->height, img->load_data.is_opaque, img->load_data.is_4byte_aligned, false, REPEAT_CLAMP);
        free_load_data(&img->load_data);
        self->used_storage += required_sz;
        img->used_storage = required_sz;
    }
    return img;
#undef MAX_DATA_SZ
#undef ABRT
}


id_filter_func(const ImageRef UNUSED *ref, Image *img, const void *data, CellPixelSize cell UNUSED) {
    uint32_t iid = *(uint32_t*)data;
    return img->client_id == iid;
}


grman_rescale(GraphicsManager *self, CellPixelSize cell) {
    ImageRef *ref; Image *img;
    self->layers_dirty = true;
    for (size_t i = self->image_count; i-- > 0;) {
        img = self->images + i;
        for (size_t j = img->refcnt; j-- > 0;) {
            ref = img->refs + j;
            ref->cell_x_offset = MIN(ref->cell_x_offset, cell.width - 1);
            ref->cell_y_offset = MIN(ref->cell_y_offset, cell.height - 1);
            update_dest_rect(ref, ref->num_cols, ref->num_rows, cell);
        }
    }
}


zlib_strerror(int ret) {
#define Z(x) case x: return #x;
    static char buf[128];
    switch(ret) {
        case Z_ERRNO:
            return strerror(errno);
        default:
            snprintf(buf, sizeof(buf)/sizeof(buf[0]), "Unknown error: %d", ret);
            return buf;
        Z(Z_STREAM_ERROR);
        Z(Z_DATA_ERROR);
        Z(Z_MEM_ERROR);
        Z(Z_BUF_ERROR);
        Z(Z_VERSION_ERROR);
    }
#undef Z
}


mmap_img_file(GraphicsManager UNUSED *self, Image *img, int fd, size_t sz, off_t offset) {
    if (!sz) {
        struct stat s;
        if (fstat(fd, &s) != 0) ABRT(EBADF, "Failed to fstat() the fd: %d file with error: [%d] %s", fd, errno, strerror(errno));
        sz = s.st_size;
    }
    void *addr = mmap(0, sz, PROT_READ, MAP_SHARED, fd, offset);
    if (addr == MAP_FAILED) ABRT(EBADF, "Failed to map image file fd: %d at offset: %zd with size: %zu with error: [%d] %s", fd, offset, sz, errno, strerror(errno));
    img->load_data.mapped_file = addr;
    img->load_data.mapped_file_sz = sz;
    return true;
err:
    return false;
}

static bool send_to_gpu = true;

static bool has_add_respose = false;

#define ABRT(code, ...) { set_add_response(#code, __VA_ARGS__); goto err; }

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;

static PyMemberDef members[] = {
    {"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
    {NULL},
};

PyTypeObject GraphicsManager_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "fast_data_types.GraphicsManager",
    .tp_basicsize = sizeof(GraphicsManager),
    .tp_dealloc = (destructor)dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "GraphicsManager",
    .tp_new = new,
    .tp_methods = methods,
    .tp_members = members,
};


x_filter_func(const ImageRef *ref, Image UNUSED *img, const void *data, CellPixelSize cell UNUSED) {
    const GraphicsCommand *g = data;
    return ref->start_column <= (int32_t)g->x_offset - 1 && ((int32_t)g->x_offset - 1) < ((int32_t)(ref->start_column + ref->effective_num_cols));
}


clear_all_filter_func(const ImageRef *ref UNUSED, Image UNUSED *img, const void UNUSED *data, CellPixelSize cell UNUSED) {
    return true;
}

static bool send_to_gpu = true;

#define W(x) static PyObject* py##x(GraphicsManager UNUSED *self, PyObject *args)

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;


point3d_filter_func(const ImageRef *ref, Image *img, const void *data, CellPixelSize cell) {
    return z_filter_func(ref, img, data, cell) && point_filter_func(ref, img, data, cell);
}

#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;