func receiveProtobuf(conn *transport.Conn, inBuf []byte, t *testing.T) *proto.ServerToClient {
	response := new(proto.ServerToClient)
	conn.SetDeadline(time.Now().Add(time.Second))
	num, err := conn.ReadFrame(inBuf)
	handleError(err, t)
	unpadMsg := proto.Unpad(inBuf[:num])
	if err := response.Unmarshal(unpadMsg); err != nil {
		t.Error(err)
	}
	if response.Status == nil {
		t.Error("Server returned nil status.")
	}
	if *response.Status == proto.ServerToClient_PARSE_ERROR {
		t.Error("Server threw a parse error.")
	}
	return response
}
func ReceiveProtobuf(conn *transport.Conn, inBuf []byte) (*proto.ServerToClient, error) {
	response := new(proto.ServerToClient)
	conn.SetDeadline(time.Now().Add(time.Hour))
	num, err := conn.ReadFrame(inBuf)
	if err != nil {
		return nil, err
	}
	unpadMsg := proto.Unpad(inBuf[:num])
	if err := response.Unmarshal(unpadMsg); err != nil {
		return nil, err
	}
	if response.Status == nil {
		return nil, errors.New("Server returned nil status.")
	}
	if *response.Status != proto.ServerToClient_OK {
		return nil, errors.New("Server did not return OK")
	}
	return response, nil
}
Beispiel #3
0
//for each client, listen for commands
func (server *Server) handleClient(connection net.Conn) error {
	defer server.wg.Done()
	newConnection, uid, err := transport.Handshake(connection, server.pk, server.sk, nil, proto.SERVER_MESSAGE_SIZE) //TODO: Decide on this bound
	if err != nil {
		return err
	}

	commands := make(chan *proto.ClientToServer)
	disconnected := make(chan error)
	server.wg.Add(2)
	go server.readClientCommands(newConnection, commands, disconnected)
	go server.handleClientShutdown(newConnection)

	var notificationsUnbuffered, notifications chan *MessageWithId
	var notifyEnabled bool
	defer func() {
		if notifyEnabled {
			server.notifier.StopWaitingSync(uid, notificationsUnbuffered)
		}
	}()

	outBuf := make([]byte, proto.SERVER_MESSAGE_SIZE)
	response := new(proto.ServerToClient)
	for {
		select {
		case err := <-disconnected:
			return err
		case cmd := <-commands:
			if cmd.CreateAccount != nil && *cmd.CreateAccount {
				err = server.newUser(uid)
			} else if cmd.DeliverEnvelope != nil {
				msg_id, err := server.newMessage((*[32]byte)(cmd.DeliverEnvelope.User),
					cmd.DeliverEnvelope.Envelope)
				if err != nil {
					return err
				}
				response.MessageId = (*proto.Byte32)(msg_id)
			} else if cmd.ListMessages != nil && *cmd.ListMessages {
				var messageList []*[32]byte
				messageList, err = server.getMessageList(uid)
				response.MessageList = proto.ToProtoByte32List(messageList)
			} else if cmd.DownloadEnvelope != nil {
				response.Envelope, err = server.getEnvelope(uid, (*[32]byte)(cmd.DownloadEnvelope))
				response.MessageId = cmd.DownloadEnvelope
			} else if cmd.DeleteMessages != nil {
				messageList := cmd.DeleteMessages
				err = server.deleteMessages(uid, proto.To32ByteList(messageList))
			} else if cmd.UploadSignedKeys != nil {
				err = server.newKeys(uid, cmd.UploadSignedKeys)
			} else if cmd.GetSignedKey != nil {
				response.SignedKey, err = server.getKey((*[32]byte)(cmd.GetSignedKey))
			} else if cmd.GetNumKeys != nil {
				response.NumKeys, err = server.getNumKeys(uid)
			} else if cmd.ReceiveEnvelopes != nil {
				if *cmd.ReceiveEnvelopes && !notifyEnabled {
					notifyEnabled = true
					notificationsUnbuffered = server.notifier.StartWaiting(uid)
					notifications = make(chan *MessageWithId)
					server.wg.Add(1)
					go server.readClientNotifications(notificationsUnbuffered, notifications)
				} else if !*cmd.ReceiveEnvelopes && notifyEnabled {
					server.notifier.StopWaitingSync(uid, notificationsUnbuffered)
					notifyEnabled = false
				}
			}
			if err != nil {
				fmt.Printf("Server error: %v\n", err)
				response.Status = proto.ServerToClient_PARSE_ERROR.Enum()
			} else {
				response.Status = proto.ServerToClient_OK.Enum()
			}
			if err = server.writeProtobuf(newConnection, outBuf, response); err != nil {
				return err
			}
			commands <- cmd
		case notification, ok := <-notifications:
			if !notifyEnabled {
				continue
			}
			if !ok {
				notifyEnabled = false
				go server.notifier.StopWaitingSync(uid, notificationsUnbuffered)
				continue
			}
			response.Envelope = notification.Envelope
			response.MessageId = (*proto.Byte32)(notification.Id)
			response.Status = proto.ServerToClient_OK.Enum()
			if err = server.writeProtobuf(newConnection, outBuf, response); err != nil {
				return err
			}
		}
		response.Reset()
	}
}