func (srv *LspServer) iRead() (uint16, []byte, error) {
	m := <-srv.appReadChan
	switch m.Type {
	case MsgDATA:
		return m.ConnId, m.Payload, nil
	case MsgINVALID:
		// Indicates that read should fail.
		return m.ConnId, nil, lsplog.ConnectionClosed()
	}
	return m.ConnId, nil, lsplog.ConnectionClosed()
}
func (cli *LspClient) iRead() ([]byte, error) {
	m := <-cli.appReadChan
	switch m.Type {
	case MsgDATA:
		return m.Payload, nil
	case MsgINVALID:
		// Indicates that read should fail
		// Recycle message so that future reads will also fail
		cli.appReadChan <- m
		return nil, lsplog.ConnectionClosed()
	}
	return nil, lsplog.ConnectionClosed()
}
func (cli *LspClient) iRead() ([]byte, error) {
	select {
	case <-cli.eventHandClosedChan:
		cli.eventHandClosed = true
		return nil, lsplog.ConnectionClosed()
	default:
		if cli.eventHandClosed {
			return nil, lsplog.ConnectionClosed()
		}
		<-cli.Rchan
		msg := <-cli.RBchan
		if msg == nil {
			return nil, lsplog.ConnectionClosed()
		}
		return msg.Payload, nil
	}
	return nil, lsplog.ConnectionClosed()
}
// Read next message received by server, return connection ID + contents
func (srv *LspServer) iRead() (uint16, []byte, error) {

	select {
	case <-srv.eventHandClosedChan:
		srv.eventHandClosed = true
		return 0, nil, lsplog.ConnectionClosed()
	default:
		if srv.eventHandClosed {
			return 0, nil, lsplog.ConnectionClosed()
		}
		<-srv.Rchan
		msg := <-srv.RBchan
		if msg == nil {
			return 0, nil, lsplog.ConnectionClosed()
		}
		if msg.Type == MsgINVALID {
			return msg.ConnId, nil, lsplog.ConnectionClosed()
		}
		return msg.ConnId, msg.Payload, nil
	}
	return 0, nil, lsplog.ConnectionClosed()
}
// Main client loop
func (cli *LspClient) clientLoop() {
	for !(cli.stopAppFlag && cli.lspConn.stopNetworkFlag) {
		if cli.readBuf.Empty() {
			select {
			case netm := <-cli.netInChan:
				cli.handleNetMessage(netm)
			case appm := <-cli.appWriteChan:
				cli.handleAppWrite(appm)
			case <-cli.epochChan:
				cli.handleEpoch()
			}
		} else {
			v := cli.readBuf.Front()
			rm := v.(*LspMessage)
			if rm.Type == MsgINVALID {
				// Have completed all reads.  Stop applications
				cli.stopAppFlag = true
			}
			select {
			case netm := <-cli.netInChan:
				cli.handleNetMessage(netm)
			case appm := <-cli.appWriteChan:
				cli.handleAppWrite(appm)
			case <-cli.epochChan:
				cli.handleEpoch()
			case cli.appReadChan <- rm:
				cli.readBuf.Remove()
			}
		}
		cli.checkToSend()
	}
	// Make sure any subsequent operations fail
	cli.closeReplyChan <- nil
	cli.writeReplyChan <- lsplog.ConnectionClosed()
	cm := GenInvalidMessage(0, 0)
	cli.appReadChan <- cm
}
// go routine to handle writing and epochs events
func EventHandlerClient(cli *LspClient) {
	for cli.running || cli.readList.Len() != 0 || cli.NbWrite != 0 {
		if cli.readList.Len() == 0 {
			select {
			case msg, _ := <-cli.WBchan:
				if !cli.running {
					cli.errChan <- lsplog.ConnectionClosed()
					continue
				}
				cli.errChan <- nil
				msg.SeqNum = cli.sn
				cli.sn++
				if cli.sn == 0 {
					cli.sn = 1
				}
				if cli.AckWrite && cli.writeList.Len() == 0 {
					select {
					case cli.Wchan <- 1:
					default:
					}
				}
				cli.writeList.PushBack(msg)
				cli.NbWrite++
			case msg, _ := <-cli.Nchan:
				cli.epochCount = 0
				switch msg.Type {
				case MsgACK:
					if cli.id == 0 && msg.SeqNum == 0 {
						cli.NbWrite--
						cli.id = msg.ConnId
						cli.established <- 1
						cli.AckWrite = true
						if cli.writeList.Len() != 0 {
							select {
							case cli.Wchan <- 1:
							default:
							}
						}
					} else if msg.ConnId == cli.id && msg.SeqNum == cli.lastWrite.SeqNum && !cli.AckWrite {
						cli.NbWrite--
						cli.AckWrite = true
						if cli.writeList.Len() != 0 {
							select {
							case cli.Wchan <- 1:
							default:
							}
						}
					}
				case MsgDATA:
					if !cli.running {
						continue
					}
					if msg.SeqNum == cli.rcvn {
						cli.rcvn++
						if cli.rcvn == 0 {
							cli.rcvn = 1
						}
						//cli.epochCount = 0
						cli.readList.PushBack(msg)
						cli.lastRead = msg
						// send an ACK
						ack, _ := buildMSG(MsgACK, msg.ConnId, msg.SeqNum, nil)
						msgAck, _ := marshalMSG(ack)
						cli.conn.Write(msgAck)
					}
				}
			case <-cli.Wchan:
				cli.AckWrite = false
				cli.lastWrite = (cli.writeList.Remove(cli.writeList.Front())).(*LspMessage)
				b, _ := marshalMSG(cli.lastWrite)
				cli.conn.Write(b)
			case <-cli.Echan:
				if !cli.AckWrite {
					b, _ := marshalMSG(cli.lastWrite)
					cli.conn.Write(b)
				}
				if cli.lastRead != nil {
					ack, _ := buildMSG(MsgACK, cli.lastRead.ConnId, cli.lastRead.SeqNum, nil)
					msgAck, _ := marshalMSG(ack)
					cli.conn.Write(msgAck)
				} else {
					ack, _ := buildMSG(MsgACK, cli.id, 0, nil)
					msgAck, _ := marshalMSG(ack)
					cli.conn.Write(msgAck)
				}
				cli.epochCount++
				if cli.epochCount == cli.params.EpochLimit {
					cli.exitEpochHandler <- 1
				} else {
					<-cli.continueEpochHandler
				}
				cli.EchanBack <- 1
			case <-cli.CloseChanEpoch:
				cli.writeList = new(list.List)
				cli.running = false
				cli.AckWrite = true
				cli.NbWrite = 0
				cli.conn.Close()
				cli.CloseNetworkChan <- 1
			case <-cli.CloseChan:
				cli.readList = new(list.List)
				cli.running = false
			}

		} else {
			select {
			case msg, _ := <-cli.WBchan:
				if !cli.running {
					cli.errChan <- lsplog.ConnectionClosed()
					continue
				}
				cli.errChan <- nil
				msg.SeqNum = cli.sn
				cli.sn++
				if cli.sn == 0 {
					cli.sn = 1
				}
				if cli.AckWrite && cli.writeList.Len() == 0 {
					select {
					case cli.Wchan <- 1:
					default:
					}
				}
				cli.writeList.PushBack(msg)
				cli.NbWrite++
			case cli.Rchan <- 1:
				cli.RBchan <- (cli.readList.Remove(cli.readList.Front())).(*LspMessage)
			case msg, _ := <-cli.Nchan:
				cli.epochCount = 0
				switch msg.Type {
				case MsgACK:
					if cli.id == 0 && msg.SeqNum == 0 {
						cli.NbWrite--
						cli.id = msg.ConnId
						cli.established <- 1
						cli.AckWrite = true
						if cli.writeList.Len() != 0 {
							select {
							case cli.Wchan <- 1:
							default:
							}
						}
					} else if msg.ConnId == cli.id && msg.SeqNum == cli.lastWrite.SeqNum && !cli.AckWrite {
						cli.NbWrite--
						cli.AckWrite = true
						if cli.writeList.Len() != 0 {
							select {
							case cli.Wchan <- 1:
							default:
							}
						}
					}
				case MsgDATA:
					if !cli.running {
						continue
					}
					if msg.SeqNum == cli.rcvn {
						cli.rcvn++
						if cli.rcvn == 0 {
							cli.rcvn = 1
						}
						//cli.epochCount = 0
						cli.readList.PushBack(msg)
						cli.lastRead = msg
						// send an ACK
						ack, _ := buildMSG(MsgACK, msg.ConnId, msg.SeqNum, nil)
						msgAck, _ := marshalMSG(ack)
						cli.conn.Write(msgAck)
					}
				}
			case <-cli.Wchan:
				cli.AckWrite = false
				cli.lastWrite = (cli.writeList.Remove(cli.writeList.Front())).(*LspMessage)
				b, _ := marshalMSG(cli.lastWrite)
				cli.conn.Write(b)
			case <-cli.Echan:
				if !cli.AckWrite {
					b, _ := marshalMSG(cli.lastWrite)
					cli.conn.Write(b)
				}
				if cli.lastRead != nil {
					ack, _ := buildMSG(MsgACK, cli.lastRead.ConnId, cli.lastRead.SeqNum, nil)
					msgAck, _ := marshalMSG(ack)
					cli.conn.Write(msgAck)
				} else {
					ack, _ := buildMSG(MsgACK, cli.id, 0, nil)
					msgAck, _ := marshalMSG(ack)
					cli.conn.Write(msgAck)
				}
				cli.epochCount++
				if cli.epochCount == cli.params.EpochLimit {
					cli.exitEpochHandler <- 1
				} else {
					<-cli.continueEpochHandler
				}
				cli.EchanBack <- 1
			case <-cli.CloseChanEpoch:
				cli.writeList = new(list.List)
				cli.AckWrite = true
				cli.running = false
				cli.NbWrite = 0
				cli.conn.Close()
				cli.CloseNetworkChan <- 1
			case <-cli.CloseChan:
				cli.readList = new(list.List)
				cli.running = false
			}
		}
	}
	cli.eventHandClosedChan <- 1
	cli.CloseNetworkChan <- 1
	cli.exitEpochHandler <- 1
	cli.conn.Close()
	cli.writeEnded <- 1
	select {
	case cli.Rchan <- 1:
		cli.RBchan <- nil
	default:
	}
}
// go routine to handle writing and epochs events
func EventHandlerServer(srv *LspServer) {
	for srv.running || srv.NbWrite != 0 || srv.readList.Len() != 0 {
		if srv.readList.Len() == 0 {
			select {
			case msg, _ := <-srv.WBchan:
				if !srv.running || !srv.ClientDict[msg.ConnId].readClient {
					srv.errChan <- lsplog.ConnectionClosed()
					continue
				}
				srv.errChan <- nil
				msg.SeqNum = srv.ClientDict[msg.ConnId].sn
				srv.ClientDict[msg.ConnId].sn++
				if srv.ClientDict[msg.ConnId].sn == 0 {
					srv.ClientDict[msg.ConnId].sn = 1
				}
				select {
				case srv.Wchan <- 1:
				default:
				}
				srv.ClientDict[msg.ConnId].writeList.PushBack(msg)
				srv.NbWrite++
			case msg, _ := <-srv.Nchan:
				if !srv.running && srv.NbWrite == 0 {
					continue
				}
				srv.epochCount = 0
				if msg.ConnId != 0 {
					srv.ClientDict[msg.ConnId].epochCount = 0
				}
				switch msg.Type {
				case MsgCONNECT:
					if msg.SeqNum == 0 && msg.ConnId == 0 {
						// connect request
						newcli := new(iClient)
						newcli.id = srv.connId
						newcli.readClient = true
						newcli.writeClient = true
						newcli.sn = 1
						newcli.epochCount = 0
						newcli.rcvn = 1
						newcli.lastSeqAcked = 0
						newcli.AckWrite = true
						newcli.writeList = new(list.List)
						newcli.clientAddr = <-srv.Addrchan
						newcli.lastRead = msg
						srv.ClientDict[srv.connId] = newcli
						ack, _ := buildMSG(MsgACK, srv.connId, 0, nil)
						msgAck, _ := marshalMSG(ack)
						srv.conn.WriteToUDP(msgAck, newcli.clientAddr)
						srv.connId++
					}
				case MsgACK:
					if msg.SeqNum == 0 {
						continue
					}
					front := srv.ClientDict[msg.ConnId].lastWrite
					if msg.SeqNum == front.SeqNum && msg.SeqNum != srv.ClientDict[msg.ConnId].lastSeqAcked {
						//srv.epochCount = 0
						srv.ClientDict[msg.ConnId].lastSeqAcked = msg.SeqNum
						srv.ClientDict[msg.ConnId].AckWrite = true
						srv.NbWrite--
						if srv.ClientDict[msg.ConnId].writeList.Len() != 0 {
							select {
							case srv.Wchan <- 1:
							default:
							}
						}
					}
				case MsgDATA:
					if !srv.running {
						continue
					}
					if srv.ClientDict[msg.ConnId].readClient && msg.SeqNum == srv.ClientDict[msg.ConnId].rcvn {
						//srv.epochCount = 0
						srv.readList.PushBack(msg)
						srv.ClientDict[msg.ConnId].lastRead = msg
						srv.ClientDict[msg.ConnId].rcvn++
						if srv.ClientDict[msg.ConnId].rcvn == 0 {
							srv.ClientDict[msg.ConnId].rcvn = 1
						}
						// send an ACK
						ack, _ := buildMSG(MsgACK, msg.ConnId, msg.SeqNum, nil)
						msgAck, _ := marshalMSG(ack)
						srv.conn.WriteToUDP(msgAck, srv.ClientDict[msg.ConnId].clientAddr)
					}
				}
			case <-srv.Wchan:
				for _, v := range srv.ClientDict {
					if !v.AckWrite || v.writeList.Len() == 0 {
						continue
					}
					if !v.writeClient {
						v.writeList.Remove(v.writeList.Front())
						srv.NbWrite--
						continue
					}
					v.lastWrite = (v.writeList.Remove(v.writeList.Front())).(*LspMessage)
					v.AckWrite = false
					msgW, _ := marshalMSG(v.lastWrite)
					srv.conn.WriteToUDP(msgW, v.clientAddr)
				}
			case <-srv.Echan:
				for _, v := range srv.ClientDict {
					if !v.writeClient {
						continue
					}
					if !v.readClient && v.writeList.Len() == 0 {
						v.writeClient = false
						continue
					}
					v.epochCount++
					if v.epochCount == srv.params.EpochLimit {
						msgDisconnect, _ := buildMSG(MsgINVALID, v.id, 0, nil)
						srv.readList.PushBack(msgDisconnect)
						v.readClient = false
						v.writeClient = false
						continue
					}
					if !v.AckWrite {
						msgW, _ := marshalMSG(v.lastWrite)
						srv.conn.WriteToUDP(msgW, v.clientAddr)
					}
					if v.lastRead != nil {
						ack, _ := buildMSG(MsgACK, v.id, v.lastRead.SeqNum, nil)
						msgR, _ := marshalMSG(ack)
						srv.conn.WriteToUDP(msgR, v.clientAddr)
					} else {
						ack, _ := buildMSG(MsgACK, v.id, 0, nil)
						msgR, _ := marshalMSG(ack)
						srv.conn.WriteToUDP(msgR, v.clientAddr)
					}
				}
				srv.epochCount++
				if srv.epochCount == srv.params.EpochLimit {
					srv.exitEpochHandler <- 1
				} else {
					<-srv.continueEpochHandler
				}
				srv.EchanBack <- 1

			case <-srv.CloseChan:
				srv.running = false
				srv.readList = new(list.List)
				for _, cli := range srv.ClientDict {
					cli.readClient = false
				}

			case <-srv.CloseChanEpoch:
				srv.NbWrite = 0
				srv.CloseNetworkChan <- 1
				srv.conn.Close()
				srv.running = false
				for id, cli := range srv.ClientDict {
					msgDisconnect, _ := buildMSG(MsgINVALID, id, 0, nil)
					srv.readList.PushBack(msgDisconnect)
					cli.readClient = false
					cli.writeClient = false
				}

			case id, _ := <-srv.CloseConnChan:
				srv.ClientDict[id].readClient = false
				msgDisconnect, _ := buildMSG(MsgINVALID, id, 0, nil)
				srv.readList.PushBack(msgDisconnect)
			}

		} else {
			select {
			case srv.Rchan <- 1:
				srv.RBchan <- (srv.readList.Remove(srv.readList.Front())).(*LspMessage)
			case msg, _ := <-srv.WBchan:
				if !srv.running || !srv.ClientDict[msg.ConnId].readClient {
					srv.errChan <- lsplog.ConnectionClosed()
					continue
				}
				srv.errChan <- nil
				msg.SeqNum = srv.ClientDict[msg.ConnId].sn
				srv.ClientDict[msg.ConnId].sn++
				if srv.ClientDict[msg.ConnId].sn == 0 {
					srv.ClientDict[msg.ConnId].sn = 1
				}
				select {
				case srv.Wchan <- 1:
				default:
				}
				srv.ClientDict[msg.ConnId].writeList.PushBack(msg)
				srv.NbWrite++
			case msg, _ := <-srv.Nchan:
				if !srv.running && srv.NbWrite == 0 {
					continue
				}
				srv.epochCount = 0
				if msg.ConnId != 0 {
					srv.ClientDict[msg.ConnId].epochCount = 0
				}
				switch msg.Type {
				case MsgCONNECT:
					if msg.SeqNum == 0 && msg.ConnId == 0 {
						// connect request
						newcli := new(iClient)
						newcli.id = srv.connId
						newcli.readClient = true
						newcli.writeClient = true
						newcli.sn = 1
						newcli.rcvn = 1
						newcli.epochCount = 0
						newcli.AckWrite = true
						newcli.lastSeqAcked = 0
						newcli.writeList = new(list.List)
						newcli.clientAddr = <-srv.Addrchan
						srv.ClientDict[srv.connId] = newcli
						ack, _ := buildMSG(MsgACK, srv.connId, 0, nil)
						msgAck, _ := marshalMSG(ack)
						srv.conn.WriteToUDP(msgAck, newcli.clientAddr)
						srv.connId++
					}
				case MsgACK:
					if msg.SeqNum == 0 {
						continue
					}
					front := srv.ClientDict[msg.ConnId].lastWrite
					if msg.SeqNum == front.SeqNum && msg.SeqNum != srv.ClientDict[msg.ConnId].lastSeqAcked {
						//srv.epochCount = 0
						srv.ClientDict[msg.ConnId].lastSeqAcked = msg.SeqNum
						srv.ClientDict[msg.ConnId].AckWrite = true
						srv.NbWrite--
						if srv.ClientDict[msg.ConnId].writeList.Len() != 0 {
							select {
							case srv.Wchan <- 1:
							default:
							}
						}
					}
				case MsgDATA:
					if !srv.running {
						continue
					}
					if srv.ClientDict[msg.ConnId].readClient && msg.SeqNum == srv.ClientDict[msg.ConnId].rcvn {
						//srv.epochCount = 0
						srv.readList.PushBack(msg)
						srv.ClientDict[msg.ConnId].lastRead = msg
						srv.ClientDict[msg.ConnId].rcvn++
						if srv.ClientDict[msg.ConnId].rcvn == 0 {
							srv.ClientDict[msg.ConnId].rcvn = 1
						}
						// send an ACK
						ack, _ := buildMSG(MsgACK, msg.ConnId, msg.SeqNum, nil)
						msgAck, _ := marshalMSG(ack)
						srv.conn.WriteToUDP(msgAck, srv.ClientDict[msg.ConnId].clientAddr)
					}
				}
			case <-srv.Wchan:
				for _, v := range srv.ClientDict {
					if !v.AckWrite || v.writeList.Len() == 0 {
						continue
					}
					if !v.writeClient {
						v.writeList.Remove(v.writeList.Front())
						srv.NbWrite--
						continue
					}
					v.lastWrite = (v.writeList.Remove(v.writeList.Front())).(*LspMessage)
					v.AckWrite = false
					msgW, _ := marshalMSG(v.lastWrite)
					srv.conn.WriteToUDP(msgW, v.clientAddr)
				}
			case <-srv.Echan:
				for _, v := range srv.ClientDict {
					if !v.writeClient {
						continue
					}
					if !v.readClient && v.writeList.Len() == 0 {
						v.writeClient = false
						continue
					}
					v.epochCount++
					if v.epochCount == srv.params.EpochLimit {
						msgDisconnect, _ := buildMSG(MsgINVALID, v.id, 0, nil)
						srv.readList.PushBack(msgDisconnect)
						v.readClient = false
						v.writeClient = false
						continue
					}
					if !v.AckWrite {
						msgW, _ := marshalMSG(v.lastWrite)
						srv.conn.WriteToUDP(msgW, v.clientAddr)
					}
					if v.lastRead != nil {
						ack, _ := buildMSG(MsgACK, v.id, v.lastRead.SeqNum, nil)
						msgR, _ := marshalMSG(ack)
						srv.conn.WriteToUDP(msgR, v.clientAddr)
					} else {
						ack, _ := buildMSG(MsgACK, v.id, 0, nil)
						msgR, _ := marshalMSG(ack)
						srv.conn.WriteToUDP(msgR, v.clientAddr)
					}
				}
				srv.epochCount++
				if srv.epochCount == srv.params.EpochLimit {
					srv.exitEpochHandler <- 1
				} else {
					<-srv.continueEpochHandler
				}
				srv.EchanBack <- 1
			case <-srv.CloseChan:
				srv.running = false
				srv.readList = new(list.List)
				for _, cli := range srv.ClientDict {
					cli.readClient = false
				}

			case <-srv.CloseChanEpoch:
				srv.NbWrite = 0
				srv.CloseNetworkChan <- 1
				srv.conn.Close()
				srv.running = false
				for id, cli := range srv.ClientDict {
					msgDisconnect, _ := buildMSG(MsgINVALID, id, 0, nil)
					srv.readList.PushBack(msgDisconnect)
					cli.readClient = false
					cli.writeClient = false
				}

			case id, _ := <-srv.CloseConnChan:
				srv.ClientDict[id].readClient = false
				msgDisconnect, _ := buildMSG(MsgINVALID, id, 0, nil)
				srv.readList.PushBack(msgDisconnect)
			}
		}
	}
	srv.eventHandClosedChan <- 1
	srv.conn.Close()
	srv.exitEpochHandler <- 1
	srv.CloseNetworkChan <- 1
	srv.writeEnded <- 1
	select {
	case srv.Rchan <- 1:
		srv.RBchan <- nil
	default:
	}
}