Library Proofchat.theories.Client

Client

In this section, we define program logic for client connections

Require Import Messages.
Require Import Monads.
Require Import OCamlTypes.
Require Import Recdef.
Open Scope monad_scope.
Open Scope sint63_scope.

The internal loop of our client sending thread
Definition client_send_thread (uname_sockfd : username × file_descr) : optionE unit :=
    let '(uname, sockfd) := uname_sockfd in
    repeat_until_timeout max_int (fun _
        let× _ print_string ">>> " #;
        msg <- read_line tt ;;
        match ((if (1 <? int_len_string msg) then
            
            if (msg =? "!exit")%string then
                _ <- send_message sockfd (serialize_client_message (EXIT uname)) ;;
                return exit tt
            
            else let first_char := match get 0 msg with
                              | Some aa
                              
                              | Nonespace
                              end in
            if Ascii.eqb first_char ampersand then
                
                let split_idx := match index 0 space_str msg with
                                 | NoneO
                                 | Some nn
                                 end in
                let msg_text :=
                    substring (split_idx + 1)
                        (Z.to_nat (to_Z (int_len_string msg)) - split_idx) msg in
                let uname_text :=
                    substring 1 (split_idx - 1) msg in
                uname <- new_username uname_text ;;
                send_message sockfd (serialize_client_message (PMSG msg_text uname))
            else
                send_message sockfd (serialize_client_message
                    (MESG msg))
        else
            SomeE tt)) with
        | SomeE _SomeE Recurse
        | NoneE s
            let× _ log Log_Error s #;
            SomeE Recurse
        end
    ).

The internal loop of our client receiving thread
Definition client_recv_thread (sockfd : file_descr) : optionE unit :=
    repeat_until_timeout max_int (fun _
        server_msg <- recv_server_message sockfd ;;
        let× _ (match server_msg with
        | MSG uname msg
            let× _ print_endline (uname.(Uname) ++ ": " ++ msg) #;
            print_string ">>> "
        | ERR err
            let× _ print_endline "" #;
            let× _ log Log_Error (string_of_error err) #;
            print_string ">>> "
        | _tt
        end) #;
        SomeE Recurse
    ).

Wraps up all client logic: port binding, threading, etc.
Definition client (host : string) (portno : port) : optionE unit :=
    
    let× _ print_endline "Please enter a username (length 1-32, no spaces)" #;
    username_string <- read_line tt ;;
    uname <- new_username username_string ;;
    
    let socket_fd := socket PF_INET SOCK_STREAM 0 in
    let socket_addr := ADDR_INET (inet_addr_of_string host) portno in
    let× _ log Log_Debug ("Opening client connection to " ++
        (string_of_socket_addr socket_addr) ++ " as " ++
        (string_of_socket_addr (getsockname socket_fd))) #;
    let× _ connect socket_fd socket_addr #;
    
    _ <- send_message socket_fd (serialize_client_message (REG uname)) ;;
    
    server_ack <- recv_server_message socket_fd ;;
    num_users <- (match server_ack with
                  | ACK num_users _return num_users
                  | ERR sfail (string_of_error s)
                  | _fail "Server denied connection"
                  end) ;;
    let× _ log Log_Info "Server accepted connection" #;
    
    let× _ log Log_Info ("Total users: " ++ (string_of_int num_users)) #;
    
    input_thread <- create (username ×file_descr) (optionE unit) client_send_thread (uname, socket_fd) ;;
    
    recv_thread <- create file_descr (optionE unit) client_recv_thread socket_fd ;;
    let× _ join input_thread #;
    
    let× _ log Log_Info "Closing connection to server" #;
    let× _ close socket_fd #;
    return tt.