Ejemplo n.º 1
0
// NewClient creates, initiates, and returns a new client. This function
// should return after a connection with the server has been established
// (i.e., the client has received an Ack message from the server in response
// to its connection request), and should return a non-nil error if a
// connection could not be made (i.e., if after K epochs, the client still
// hasn't received an Ack message from the server in response to its K
// connection requests).
//
// hostport is a colon-separated string identifying the server's host address
// and port number (i.e., "localhost:9999").
func NewClient(hostport string, params *Params) (Client, error) {
	if params == nil {
		params = &Params{5, 2000, 1}
	}

	addr, err := lspnet.ResolveUDPAddr("udp", hostport)
	if err != nil {
		return nil, err
	}

	conn, err := lspnet.DialUDP("udp", nil, addr)
	if err != nil {
		return nil, err
	}

	c := &client{
		comm:    NewCommon(addr, params),
		connUDP: conn,

		readBufToAppChan:   make(chan *Message),
		netToReadWinChan:   make(chan *Message),
		epochToReadWinChan: make(chan *Message),

		appToWriteBufChan:   make(chan *Message),
		netToWriteBufChan:   make(chan *Message),
		epochToWriteBufChan: make(chan *Message),

		connChan: make(chan *Message),

		appCloseSynChan:     make(chan bool, 1),
		netLostCloseSynChan: make(chan bool, 1),
	}

	// go c.manageReceivedMsg()
	go c.handleEpoch()
	go c.readFromServer()
	go c.handleReadSlideWindow()
	go c.handleWriteSlideWindow()

	//init lock
	// c.connIDSynChan <- 0

	c.appCloseSynChan <- false
	c.netLostCloseSynChan <- false

	//start connect
	c.writeToServer(c.generateMsg(MsgConnect, 0, nil))
	connMsg := <-c.connChan
	if connMsg.Type == MsgAck && connMsg.SeqNum == 0 {
		SetValueToIntChan(c.comm.connIDSynChan, connMsg.ConnID)
		SetValueToBoolChan(c.comm.isConnectedSynChan, true)
		c.comm.connID = connMsg.ConnID
		fmt.Println("Client:", c.comm.connID, "Start")
		return c, nil
	}
	return nil, errors.New("Connection failed")
}
Ejemplo n.º 2
0
// listen to incoming UDP data using the given hostport, used on server side
func (h *networkUtility) listen(hostport string) error {
	serverAddr, err := lspnet.ResolveUDPAddr("udp", hostport)
	if err != nil {
		return nil
	}
	conn, err := lspnet.ListenUDP("udp", serverAddr)
	if err != nil {
		return err
	}
	h.conn = conn
	return nil
}
Ejemplo n.º 3
0
func (now *Connect) listen(hostport string) error {
	serverAddr, err := lspnet.ResolveUDPAddr("udp", hostport)
	if err != nil {
		return nil
	}
	conn, err := lspnet.ListenUDP("udp", serverAddr)
	if err != nil {
		return err
	}
	now.conn = conn
	now.addr = serverAddr
	return nil
}
Ejemplo n.º 4
0
func (now *Connect) dial(hostport string) error {
	serverAddr, err := lspnet.ResolveUDPAddr("udp", hostport)
	if err != nil {
		return err
	}
	conn, err := lspnet.DialUDP("udp", nil, serverAddr)
	if err != nil {
		return err
	}
	now.addr = serverAddr
	now.conn = conn
	return nil
}
func (s *server) StartListen(port string) error {
	uAddr, err := lspnet.ResolveUDPAddr("udp", ":"+port)
	if err != nil {
		fmt.Println("Unable to resolve UDP addr ", port)
		return err
	}
	s.sConn, err = lspnet.ListenUDP("udp", uAddr)
	if err != nil {
		fmt.Println("Unable to listen on port ", port)
		return err
	}

	go s.handleMessages()
	go s.ticking()

	for {
		select {
		case <-s.quitAllChan:
			fmt.Println("server quit listener")
			return nil
		default:
			// read a msg from UDP and check its type
			buf := make([]byte, 2000)
			n, addr, err := s.sConn.ReadFromUDP(buf)
			if err != nil {
				return err
			}
			msg := Message{}
			json.Unmarshal(buf[0:n], &msg)
			switch msg.Type {
			case MsgConnect:
				// receive a conn msg from client
				s.addChan <- addr
			case MsgData:
				// add to data channel if hash match, drop otherwise
				if hex.EncodeToString(calMD5Hash(msg)) == hex.EncodeToString(msg.Hash) {
					s.dataChan <- &msg
				} else {
					fmt.Println("Hash does not match")
				}
			case MsgAck:
				s.ackChan <- &msg
			}
		}
	}
	return err
}
Ejemplo n.º 6
0
func NewFixedSizeUDPServer(maxMsgSize int, port int) (UDPServer, error) {
	addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf(":%v", port))
	if err != nil {
		return nil, err
	}

	conn, err := net.ListenUDP("udp", addr) // non-blocking. no need to wait for any client to establish a connection like TCP does
	if err != nil {
		return nil, err
	}

	return &FixedSizeUDPServer{
		maxMsgSize: maxMsgSize,
		addr:       addr,
		conn:       conn,
		closed:     false,
	}, nil
}
func (c *client) StartDial(hostport string) error {
	var err error
	c.sAddr, err = lspnet.ResolveUDPAddr("udp", hostport)
	if err != nil {
		fmt.Println("Unable to resolve server UDP addr ", hostport)
		return err
	}
	go c.handleMessages()
	go c.ticking()

	c.conn, err = lspnet.DialUDP("udp", nil, c.sAddr)

	if err != nil {
		fmt.Println("cannot dial to port ", hostport)
		return err
	}

	fmt.Println("dial to ", hostport)

	// send connect message
	c.writeChan <- clientWriteData{MsgConnect, 0, nil}

	// waiting for connect ack
	buf := make([]byte, 2000)
	msg := Message{}
	n, err := c.conn.Read(buf)
	if err != nil {
		fmt.Println("unable read from connection")
		msg = <-c.connSucChan
	} else {
		json.Unmarshal(buf[0:n], &msg)
	}
	switch msg.Type {
	case MsgAck:
		c.setidChan <- msg.ConnID
	default:
		return errors.New("unable to connect")
	}

	// start listen on data/ack
	go c.StartListen()

	return nil
}
Ejemplo n.º 8
0
func NewFixedSizeUDPClient(maxMsgSize int, serverHostPort string) (UDPClient, error) {
	serverAddr, err := net.ResolveUDPAddr("udp4", serverHostPort)
	if err != nil {
		return nil, err
	}

	// non-blocking. it won't wait for server to build connection as TCP does
	// it returns non-nil error even though the server is not running. (no connection)
	conn, err := net.DialUDP("udp", nil, serverAddr)
	if err != nil {
		return nil, err
	}

	return &FixedSizeUDPClient{
		maxMsgSize: maxMsgSize,
		serverAddr: serverAddr,
		conn:       conn,
		closed:     false,
	}, nil
}
Ejemplo n.º 9
0
// NewServer creates, initiates, and returns a new server. This function should
// NOT block. Instead, it should spawn one or more goroutines (to handle things
// like accepting incoming client connections, triggering epoch events at
// fixed intervals, synchronizing events using a for-select loop like you saw in
// project 0, etc.) and immediately return. It should return a non-nil error if
// there was an error resolving or listening on the specified port number.
func NewServer(port int, params *Params) (Server, error) {
	s := &server{
		nextConnectId:      1,
		clients:            make(map[int]*abstractClient),
		readFromClientChan: make(chan *msgPackage),
		writeToClientChan:  make(chan *Message),
		readRequest: &requestRead{
			ask:      make(chan int),
			response: make(chan *Message),
		},
		writeRequest: &requestWrite{
			ask:      make(chan []byte),
			connId:   make(chan int),
			response: make(chan error),
		},
		readList:  list.New(),
		writeList: list.New(),

		flag: false,

		// variables for window size
		windowSize:  params.WindowSize,
		mapNeedSend: list.New(),

		// variables for epoch
		epochChan:   make(chan int),
		epochMillis: params.EpochMillis,
		epochLimit:  params.EpochLimit,

		// close
		deleteClient: make(chan int),
		closeConnRequest: &requestCloseConn{
			ask:      make(chan int),
			getError: make(chan error),
		},
		waitToWriteFinish: false,
		writeFinished:     make(chan int),
		waitToAckFinish:   false,
		ackFinished:       make(chan int),
		closeRead:         make(chan int, 1),
		closeEpoch:        make(chan int, 1),
		closeEvent:        make(chan int, 1),

		// close conn
		closeConn: make(chan int, 1),
	}

	// start server
	addr, err := lspnet.ResolveUDPAddr("udp", "localhost:"+strconv.Itoa(port))
	if err != nil {
		return nil, err
	}

	conn, err := lspnet.ListenUDP("udp", addr)
	if err != nil {
		return nil, err
	}

	s.conn = conn
	go s.readMessage()
	go s.handleMessage()
	go s.epochFire()

	fmt.Println("new server")
	return s, nil
}
Ejemplo n.º 10
0
// NewClient creates, initiates, and returns a new client. This function
// should return after a connection with the server has been established
// (i.e., the client has received an Ack message from the server in response
// to its connection request), and should return a non-nil error if a
// connection could not be made (i.e., if after K epochs, the client still
// hasn't received an Ack message from the server in response to its K
// connection requests).
//
// hostport is a colon-separated string identifying the server's host address
// and port number (i.e., "localhost:9999").
func NewClient(hostport string, params *Params) (Client, error) {
	c := &client{
		nextSN:             1,
		writeToServerChan:  make(chan *Message),
		readFromServerChan: make(chan *Message),
		readRequest: &requestRead{
			ask:      make(chan int),
			response: make(chan *Message),
		},
		writeRequest: &requestWrite{
			ask:      make(chan []byte),
			response: make(chan error),
		},
		readMap: make(map[int]*Message),
		// write list has order
		writeMap:  make(map[int]*Message),
		connected: make(chan int),
		flag:      false,
		connect:   false,

		// variables for window size
		windowSize: params.WindowSize,
		// send to client data
		nextSmallestAck: 1,
		mapAck:          make(map[int]bool),
		mapNeedAck:      make(map[int]*Message),

		// receive from client data
		nextSmallestData: 1,
		// TODO: didn't need this
		mapAcked:     make(map[int]bool),
		mapReceived:  make(map[int]*Message),
		nextDataRead: 1,

		// epoch variables
		epochChan:   make(chan int),
		epochMillis: params.EpochMillis,
		epochLimit:  params.EpochLimit,
		epochNum:    0,
		lostConn:    false,

		// clsoe
		closeRequest: &requestClose{
			ask: make(chan int),
			//response: make(chan int),
			getError: make(chan error),
		},
		waitToWriteFinish: false,
		writeFinished:     make(chan int),
		waitToAckFinish:   false,
		ackFinished:       make(chan int),
		closeRead:         make(chan int, 1),
		closeEpoch:        make(chan int, 1),
		closeEvent:        make(chan int, 1),
	}

	// connect to server
	addr, err := lspnet.ResolveUDPAddr("udp", hostport)

	if err != nil {
		return nil, err
	}

	conn, err := lspnet.DialUDP("udp", nil, addr)
	if err != nil {
		return nil, err
	}
	fmt.Println("new client")

	c.conn = conn
	c.addr = addr
	fmt.Println("70")

	////fmt.Println("74")

	go c.readMessage()
	go c.handleMessage()
	go c.epochFire()

	msg := NewConnect()
	c.writeToServerChan <- msg

	<-c.connected
	//fmt.Println("Client 156: connect success")

	return c, nil
}
Ejemplo n.º 11
0
// NewClient creates, initiates, and returns a new client. This function
// should return after a connection with the server has been established
// (i.e., the client has received an Ack message from the server in response
// to its connection request), and should return a non-nil error if a
// connection could not be made (i.e., if after K epochs, the client still
// hasn't received an Ack message from the server in response to its K
// connection requests).
//
// hostport is a colon-separated string identifying the server's host address
// and port number (i.e., "localhost:9999").
func NewClient(hostport string, params *Params) (Client, error) {
	c := &client{
		hostport: hostport,
		params:   params,
		connID:   -1,
		seqNum:   0,

		conn:      nil,
		connected: false,
		connOpen:  make(chan struct{}),
		connClose: make(chan struct{}),
		connMsg:   NewConnect(),

		dataMsgTo: make(chan *Message),
		dataMsgFr: make(chan *Message),

		dataMsgTokens: make(chan struct{}, params.WindowSize),

		seqNumToActChan:    make(chan map[int]*Activity),
		seqNumToAckMsgChan: make(chan map[int]*Message),

		dataWrWindow: make(chan *SlideWindow, 1),
		dataRdWindow: make(chan *SlideWindow, 1),
	}

	raddr, err := lspnet.ResolveUDPAddr("udp", hostport)
	if err != nil {
		return nil, err
	}
	conn, err := lspnet.DialUDP("udp", nil, raddr)
	if err != nil {
		return nil, err
	}

	c.conn = conn
	c.dataWrWindow <- &SlideWindow{
		seqNumLower: 1,
		seqNumUpper: 1 + c.params.WindowSize,
	}
	c.dataRdWindow <- &SlideWindow{
		seqNumLower: 1,
		seqNumUpper: 1 + c.params.WindowSize,
	}

	go c.onWrite()
	go c.onRead()
	go c.epoch()
	go c.connect()

	for {
		select {
		case <-c.connOpen:
			c.connected = true
			return c, nil
		case <-c.connClose:
			c.connected = false
			return nil, errors.New("connection not yet established")
		}
	}

	return nil, errors.New("not yet implemented")
}