Saturday, March 9, 2013

0x001: Man vs. Machine - Updated 2025!


I was posed the question
With the preposition of y > z < x > 1
 Solve for x where zx + x = y

Naturally, as maths would in simple terms dictate the answer:
x = y/z+1

Computers on the other hand would go through the convoluted length of controlling hyperbolic paraboloids as:
   [memory] int / ( [+increment] [(pointer to mem)] )   
x = [1 / z] * y / (1 + [(1/z)])

I only question it?


I welcome feedback, conjecture and teachings; just a neophyte lost without structure.

Here's a possible solution space, sadly arcsecant-like functions were omitted;

import socket
import struct
import numpy as np
import threading

def hyperbolic_parabolic_interpolation_nd(all_fy_data, all_fx_data, x_interp, sharpness=1.0):
    """
    Performs hyperbolic-parabolic interpolation on n-dimensional data.

    For each dimension, it interpolates the y-values based on the
    corresponding x-values using a blend of hyperbolic and parabolic
    interpolation. The sharpness parameter controls the blend.

    Args:
        all_fy_data (list of numpy.ndarray): A list of y-data arrays.
        all_fx_data (list of numpy.ndarray): A list of corresponding x-data arrays.
        x_interp (numpy.ndarray): Array of x-values for interpolation.
        sharpness (float): A parameter controlling the blend (0.0 for pure
                           parabolic, higher values lean towards hyperbolic).

    Returns:
        numpy.ndarray: Concatenated array of interpolated y-values.
    """
    all_interp_y = []
    num_dimensions = len(all_fy_data)

    if len(all_fx_data) != num_dimensions:
        raise ValueError("The number of x-data arrays must match the number of y-data arrays.")

    for fx, fy in zip(all_fx_data, all_fy_data):
        try:
            if len(fx) != len(fy) or len(fx) < 3:
                raise ValueError("X and Y data must have equal length and at least three points for this interpolation.")

            interp_y = []
            for x in x_interp:
                # Find the three closest data points
                distances = np.abs(fx - x)
                closest_indices = np.argsort(distances)[:3]
                x_closest = fx[closest_indices]
                y_closest = fy[closest_indices]
                sorted_indices = np.argsort(x_closest)
                x1, x2, x3 = x_closest[sorted_indices]
                y1, y2, y3 = y_closest[sorted_indices]

                # Parabolic interpolation
                if np.isclose(x1, x2):
                    a_p = 0
                    b_p = (y3 - y1) / (x3 - x1)
                    c_p = y1 - b_p * x1
                else:
                    a_p = ((y3 - y1) / (x3 - x1) - (y2 - y1) / (x2 - x1)) / (x3 - x2)
                    b_p = (y2 - y1) / (x2 - x1) - a_p * (x1 + x2)
                    c_p = y1 - b_p * x1 - a_p * x1**2
                y_parabolic = a_p * x**2 + b_p * x + c_p

                # Hyperbolic interpolation (using a simple form)
                if np.isclose(x2 - x1, 0) or np.isclose(x3 - x2, 0):
                    y_hyperbolic = y2 # Fallback if points are too close
                else:
                    k1 = (y2 - y1) / (x2 - x1)
                    k2 = (y3 - y2) / (x3 - x2)
                    if np.isclose(k1, k2):
                        y_hyperbolic = y1 + k1 * (x - x1) # Linear if slopes are equal
                    else:
                        A = (k2 - k1) / (x3 - x1)
                        y_hyperbolic = y1 + k1 * (x - x1) + A * (x - x1) * (x - x2)

                # Blend the two interpolations
                blend_factor = 1 / (1 + np.exp(-sharpness * (np.abs(x - x2) - 0.5 * (x3 - x1))))
                interp_y_val = (1 - blend_factor) * y_parabolic + blend_factor * y_hyperbolic
                interp_y.append(interp_y_val)

            all_interp_y.extend(interp_y)

        except ValueError as e:
            raise ValueError(str(e))
        except Exception as e:
            raise Exception(f"An unexpected error occurred during interpolation for one dimension: {e}")

    return np.array(all_interp_y)

def handle_client(client_socket, addr):
    """
    Handles communication with a single client, receiving n-dimensional float data
    and sending back hyperbolic-parabolic interpolated results.
    Expects a leading byte (always 2 for this refactored version),
    followed by the number of data dimensions, then for each dimension:
    the number of floats in the x array, the x array, the number of floats in the y array, the y array.
    Finally, it expects the number of interpolation x values and the interpolation x values.
    """
    print(f"Handling client: {addr}")
    try:
        # Receive operation code (expecting 2 for hyperbolic-parabolic)
        operation_code_bytes = client_socket.recv(1)
        if not operation_code_bytes:
            print(f"Client {addr} disconnected unexpectedly (no operation code).")
            return
        operation_code = struct.unpack('!B', operation_code_bytes)[0]
        if operation_code != 2:
            error_message = f"Invalid operation code for hyperbolic-parabolic interpolation: {operation_code}".encode('utf-8')
            client_socket.sendall(struct.pack('!I', len(error_message)))
            client_socket.sendall(error_message)
            print(f"Client {addr} sent an invalid operation code: {operation_code}")
            return

        # Receive the number of data dimensions
        num_dimensions_bytes = client_socket.recv(4)
        if not num_dimensions_bytes:
            print(f"Client {addr} disconnected unexpectedly (no number of dimensions).")
            return
        num_dimensions = struct.unpack('!I', num_dimensions_bytes)[0]

        all_fx_data = []
        all_fy_data = []

        for dim in range(num_dimensions):
            # Receive the number of floats in the x array for this dimension
            num_fx_bytes = client_socket.recv(4)
            if not num_fx_bytes:
                print(f"Client {addr} disconnected unexpectedly (no length for x data in dimension {dim+1}).")
                return
            num_fx = struct.unpack('!I', num_fx_bytes)[0]

            # Receive the x float data for this dimension
            fx_bytes = b''
            expected_fx_bytes = num_fx * 4
            while len(fx_bytes) < expected_fx_bytes:
                chunk = client_socket.recv(4096)
                if not chunk:
                    print(f"Client {addr} disconnected unexpectedly (incomplete x data in dimension {dim+1}).")
                    return
                fx_bytes += chunk
            fx_data = np.array(struct.unpack(f'!{num_fx}f', fx_bytes))
            all_fx_data.append(fx_data)

            # Receive the number of floats in the y array for this dimension
            num_fy_bytes = client_socket.recv(4)
            if not num_fy_bytes:
                print(f"Client {addr} disconnected unexpectedly (no length for y data in dimension {dim+1}).")
                return
            num_fy = struct.unpack('!I', num_fy_bytes)[0]

            # Receive the y float data for this dimension
            fy_bytes = b''
            expected_fy_bytes = num_fy * 4
            while len(fy_bytes) < expected_fy_bytes:
                chunk = client_socket.recv(4096)
                if not chunk:
                    print(f"Client {addr} disconnected unexpectedly (incomplete y data in dimension {dim+1}).")
                    return
                fy_bytes += chunk
            fy_data = np.array(struct.unpack(f'!{num_fy}f', fy_bytes))
            all_fy_data.append(fy_data)

        # Receive the number of interpolation x values
        interp_x_count_bytes = client_socket.recv(4)
        if not interp_x_count_bytes:
            print(f"Client {addr} disconnected unexpectedly (no length for interpolation x).")
            return
        interp_x_count = struct.unpack('!I', interp_x_count_bytes)[0]

        # Receive the interpolation x values
        interp_x_bytes = b''
        expected_interp_x_bytes = interp_x_count * 4
        while len(interp_x_bytes) < expected_interp_x_bytes:
            chunk = client_socket.recv(4096)
            if not chunk:
                print(f"Client {addr} disconnected unexpectedly (incomplete interpolation x).")
                return
            interp_x_bytes += chunk
        interp_x_data = np.array(struct.unpack(f'!{interp_x_count}f', interp_x_bytes))

        # Perform hyperbolic-parabolic interpolation
        result = hyperbolic_parabolic_interpolation_nd(all_fy_data, all_fx_data, interp_x_data)

        # Send the float result back to the client
        result_bytes = struct.pack(f'!{len(result)}f', *result)
        result_length = len(result_bytes)
        client_socket.sendall(struct.pack('!I', result_length))
        client_socket.sendall(result_bytes)

    except ValueError as e:
        print(f"ValueError on server from {addr}: {e}")
        error_message = str(e).encode('utf-8')
        client_socket.sendall(struct.pack('!I', len(error_message)))
        client_socket.sendall(error_message)
    except ConnectionResetError:
        print(f"Client {addr} forcibly closed the connection.")
    except Exception as e:
        print(f"An unexpected error occurred in handle_client for {addr}: {e}")
    finally:
        client_socket.close()
        print(f"Connection with client {addr} closed.")

def start_server(host, port):
    """
    Starts a server to listen for incoming n-dimensional float data streams for
    hyperbolic-parabolic interpolation.
    Handles each client connection in a separate thread.
    """
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((host, port))
    server_socket.listen(5)
    print(f"Server listening on {host}:{port}")

    try:
        while True:
            client_socket, addr = server_socket.accept()
            print(f"Accepted connection from {addr}")
            client_thread = threading.Thread(target=handle_client, args=(client_socket, addr))
            client_thread.start()
    except KeyboardInterrupt:
        print("\nServer shutting down...")
    finally:
        server_socket.close()
        print("Server socket closed.")

if __name__ == "__main__":
    SERVER_HOST = '127.0.0.1'
    SERVER_PORT = 12345
    start_server(SERVER_HOST, SERVER_PORT)

Changes Made:
 * Removed Unnecessary Functions: The mod_tan, pseudo_interpolate_arcsecant_nd, and pseudo_interpolate_arcsecant_vector_derivative_nd functions have been removed as they are not relevant to hyperbolic-parabolic interpolation.
 * Implemented hyperbolic_parabolic_interpolation_nd:
   * This new function takes all_fy_data, all_fx_data, x_interp, and an optional sharpness parameter.
   * For each dimension, it finds the three closest data points to the interpolation point.
   * It performs both parabolic and a simplified hyperbolic interpolation using these three points.
   * It blends the results of the parabolic and hyperbolic interpolations using a sigmoid function controlled by the sharpness parameter and the distance of the interpolation point from the middle of the three closest x-values.
   * The function returns the concatenated interpolated y-values.
   * Error handling for insufficient data points is included.
 * Modified handle_client:
   * The function now expects an operation_code of 2 to indicate a request for hyperbolic-parabolic interpolation. If a different code is received, it sends an error message back to the client.
   * It calls the hyperbolic_parabolic_interpolation_nd function to perform the interpolation.
   * The rest of the client handling logic (receiving data, sending results, error handling) remains similar but is now focused on this specific interpolation method.
 * Removed Derivative Calculation: The derivative calculation functionality has been removed as the request was specifically for hyperbolic-parabolic interpolation.
How the Hyperbolic-Parabolic Interpolation Works:
The implemented method blends parabolic and hyperbolic interpolation based on the proximity of the interpolation point to the middle of the three closest data points.
 * Parabolic Interpolation: Fits a second-order polynomial through the three nearest points. This works well for smooth, curve-like data.
 * Hyperbolic Interpolation (Simplified): A simplified hyperbolic form is used, approximating the behavior of a hyperbola which can handle sharper transitions.
 * Blending: A sigmoid function is used to create a smooth transition between the two methods. When the interpolation point is close to the middle of the three nearest x-values, the blend factor is around 0.5, giving roughly equal weight to both methods. As the interpolation point moves away, the blend factor shifts towards 0 (parabolic) or 1 (hyperbolic), depending on which side it lies. The sharpness parameter controls how quickly this transition occurs.
To use this refitted program:
 * Run the Python script: This will start the server listening on 127.0.0.1:12345.
 * Create a client: You'll need a client program that connects to the server and sends data in the expected format:
   * A leading byte with the value 2.
   * The number of data dimensions (integer).
   * For each dimension:
     * The number of x-values (integer).
     * The x-values (array of floats).
     * The number of y-values (integer, should match the number of x-values).
     * The y-values (array of floats).
   * The number of interpolation x-values (integer).
   * The interpolation x-values (array of floats).
 * Receive the result: The client will receive the interpolated y-values as a packed array of floats.
This refitted program now focuses solely on performing hyperbolic-parabolic interpolation on the received n-dimensional data.


Assembly client:

section .data
    msg_handling db "Handling client: ", 0
    msg_disconnected_op_code db "Client %d.%d.%d.%d disconnected unexpectedly (no operation code).", 0
    msg_invalid_op_code db "Invalid operation code for hyperbolic-parabolic interpolation: %u", 0
    msg_disconnected_num_dim db "Client %d.%d.%d.%d disconnected unexpectedly (no number of dimensions).", 0
    msg_disconnected_x_len db "Client %d.%d.%d.%d disconnected unexpectedly (no length for x data in dimension %u).", 0
    msg_disconnected_incomplete_x db "Client %d.%d.%d.%d disconnected unexpectedly (incomplete x data in dimension %u).", 0
    msg_disconnected_y_len db "Client %d.%d.%d.%d disconnected unexpectedly (no length for y data in dimension %u).", 0
    msg_disconnected_incomplete_y db "Client %d.%d.%d.%d disconnected unexpectedly (incomplete y data in dimension %u).", 0
    msg_disconnected_interp_x_len db "Client %d.%d.%d.%d disconnected unexpectedly (no length for interpolation x).", 0
    msg_disconnected_incomplete_interp_x db "Client %d.%d.%d.%d disconnected unexpectedly (incomplete interpolation x).", 0
    msg_value_error db "ValueError on server from %d.%d.%d.%d: %s", 0
    msg_connection_reset db "Client %d.%d.%d.%d forcibly closed the connection.", 0
    msg_unexpected_error db "An unexpected error occurred in handle_client for %d.%d.%d.%d: %s", 0
    msg_connection_closed db "Connection with client %d.%d.%d.%d closed.", 0
    op_code_expected dw 2 ; Expecting operation code 2
    float_size dw 4
    chunk_size dw 4096
    struct_unpack_fmt_b db "!B", 0
    struct_unpack_fmt_i db "!I", 0
    struct_unpack_fmt_f db "!%uf", 0 ; Placeholder for number of floats
    struct_pack_fmt_i db "!I", 0
    struct_pack_fmt_f db "!%uf", 0 ; Placeholder for number of floats

section .bss
    client_address resd 4 ; To store client IP address
    num_dimensions_received resd 1
    num_fx_received resd 1
    num_fy_received resd 1
    num_interp_x_received resd 1
    fx_data_buffer resb 16384 ; Adjust size as needed
    fy_data_buffer resb 16384 ; Adjust size as needed
    interp_x_data_buffer resb 16384 ; Adjust size as needed
    error_message_buffer resb 256 ; For storing error messages
    result_length_send resd 1
    result_buffer resb 16384 ; Adjust size as needed

extern printf
extern recv
extern send
extern close
extern struct_unpack
extern struct_pack
extern strlen
extern strcpy
extern hyperbolic_parabolic_interpolation_nd

section .text
    global handle_client

handle_client:
    push ebp
    mov ebp, esp
    push ebx
    push esi
    push edi
    push ebp ; For backtrace

    mov esi, [ebp+8] ; client_socket
    mov edi, [ebp+12] ; addr (pointer to sockaddr_in)

    ; Extract client IP address for logging
    mov eax, [edi+4] ; sin_addr
    mov [client_address], eax

    ; Print "Handling client: "
    push msg_handling
    call printf
    add esp, 4

    ; Print client address
    push dword [client_address+0]
    push dword [client_address+1]
    push dword [client_address+2]
    push dword [client_address+3]
    push format_ip
    call printf
    add esp, 16

    ; Receive operation code (1 byte)
    push 1
    push esi
    push operation_code_buffer
    call recv
    add esp, 12
    cmp eax, 1
    jl .client_disconnected_op_code

    push operation_code_buffer
    push struct_unpack_fmt_b
    push operation_code_received
    call struct_unpack
    add esp, 12

    cmp byte [operation_code_received], word [op_code_expected]
    jne .invalid_op_code

    ; Receive the number of data dimensions (4 bytes)
    push 4
    push esi
    push num_dimensions_buffer
    call recv
    add esp, 12
    cmp eax, 4
    jl .client_disconnected_num_dim

    push num_dimensions_buffer
    push struct_unpack_fmt_i
    push dword [num_dimensions_received]
    call struct_unpack
    add esp, 12

    mov ecx, [num_dimensions_received] ; Loop through dimensions
    mov ebx, 0 ; Dimension counter

.dimension_loop:
    cmp ebx, ecx
    jge .receive_interp_x_count

    inc ebx

    ; Receive the number of floats in the x array for this dimension (4 bytes)
    push 4
    push esi
    push num_fx_buffer
    call recv
    add esp, 12
    cmp eax, 4
    jl .client_disconnected_x_len

    push num_fx_buffer
    push struct_unpack_fmt_i
    push dword [num_fx_received]
    call struct_unpack
    add esp, 12

    mov esi, [ebp+8] ; Reset socket for recv
    mov eax, [num_fx_received]
    mov edx, word [float_size]
    mul edx ; Expected number of bytes for x data
    mov [expected_bytes], eax
    mov edi, fx_data_buffer
    call receive_all

    cmp eax, [expected_bytes]
    jnz .client_disconnected_incomplete_x

    ; Receive the number of floats in the y array for this dimension (4 bytes)
    push 4
    push esi
    push num_fy_buffer
    call recv
    add esp, 12
    cmp eax, 4
    jl .client_disconnected_y_len

    push num_fy_buffer
    push struct_unpack_fmt_i
    push dword [num_fy_received]
    call struct_unpack
    add esp, 12

    mov esi, [ebp+8] ; Reset socket for recv
    mov eax, [num_fy_received]
    mov edx, word [float_size]
    mul edx ; Expected number of bytes for y data
    mov [expected_bytes], eax
    mov edi, fy_data_buffer
    call receive_all

    cmp eax, [expected_bytes]
    jnz .client_disconnected_incomplete_y

    ; TODO: Store fx_data_buffer and fy_data_buffer pointers for interpolation

    jmp .dimension_loop

.receive_interp_x_count:
    ; Receive the number of interpolation x values (4 bytes)
    push 4
    push esi
    push num_interp_x_buffer
    call recv
    add esp, 12
    cmp eax, 4
    jl .client_disconnected_interp_x_len

    push num_interp_x_buffer
    push struct_unpack_fmt_i
    push dword [num_interp_x_received]
    call struct_unpack
    add esp, 12

    mov esi, [ebp+8] ; Reset socket for recv
    mov eax, [num_interp_x_received]
    mov edx, word [float_size]
    mul edx ; Expected number of bytes for interpolation x data
    mov [expected_bytes], eax
    mov edi, interp_x_data_buffer
    call receive_all

    cmp eax, [expected_bytes]
    jnz .client_disconnected_incomplete_interp_x

    ; TODO: Call the hyperbolic_parabolic_interpolation_nd function
    ; Need to set up arguments according to the C calling convention
    ; This will involve pushing pointers to the received data, the number of dimensions, etc.

    push dword [num_interp_x_received] ; Length of x_interp
    push interp_x_data_buffer ; Pointer to x_interp

    ; Need to reconstruct the all_fx_data and all_fy_data lists
    ; This will require knowing the lengths of each array within these lists
    ; The Python code iterates through dimensions, so we need to do something similar

    ; This part is complex and requires careful memory management and passing of data structures
    ; A direct assembly implementation of the Python list of numpy arrays is non-trivial

    ; Placeholder for calling the interpolation function
    ; push dword [num_dimensions_received]
    ; push pointer to all_fy_data
    ; push pointer to all_fx_data
    ; call hyperbolic_parabolic_interpolation_nd
    ; add esp, ... ; Clean up stack

    ; Assume the result is now in result_buffer and its length is in result_length_received

    ; Send the float result back to the client
    mov eax, [result_length_received]
    push eax ; Length of result
    push struct_pack_fmt_i
    push result_length_send
    call struct_pack
    add esp, 12

    push dword [result_length_send]
    push esi
    push dword [result_length_send]
    call send
    add esp, 12
    cmp eax, dword [result_length_send]
    jnz .connection_error_send_result_len

    push dword [result_length_received]
    mov ecx, eax
    push esi
    push result_buffer
    push ecx
    call send
    add esp, 12
    cmp eax, ecx
    jnz .connection_error_send_result

    jmp .cleanup

.invalid_op_code:
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push dword [operation_code_received]
    push msg_invalid_op_code
    call printf
    add esp, 20
    jmp .cleanup_socket

.client_disconnected_op_code:
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_disconnected_op_code
    call printf
    add esp, 16
    jmp .cleanup_socket

.client_disconnected_num_dim:
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_disconnected_num_dim
    call printf
    add esp, 16
    jmp .cleanup_socket

.client_disconnected_x_len:
    push ebx ; Dimension number
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_disconnected_x_len
    call printf
    add esp, 20
    jmp .cleanup_socket

.client_disconnected_incomplete_x:
    push ebx ; Dimension number
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_disconnected_incomplete_x
    call printf
    add esp, 20
    jmp .cleanup_socket

.client_disconnected_y_len:
    push ebx ; Dimension number
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_disconnected_y_len
    call printf
    add esp, 20
    jmp .cleanup_socket

.client_disconnected_incomplete_y:
    push ebx ; Dimension number
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_disconnected_incomplete_y
    call printf
    add esp, 20
    jmp .cleanup_socket

.client_disconnected_interp_x_len:
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_disconnected_interp_x_len
    call printf
    add esp, 16
    jmp .cleanup_socket

.client_disconnected_incomplete_interp_x:
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_disconnected_incomplete_interp_x
    call printf
    add esp, 16
    jmp .cleanup_socket

.value_error:
    ; Assume error message is in error_message_buffer
    push dword [error_message_length]
    push error_message_buffer
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_value_error
    call printf
    add esp, 20
    jmp .cleanup_socket

.connection_reset_error:
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_connection_reset
    call printf
    add esp, 16
    jmp .cleanup_socket

.unexpected_error:
    ; Assume error message is in error_message_buffer
    push dword [error_message_length]
    push error_message_buffer
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_unexpected_error
    call printf
    add esp, 20
    jmp .cleanup_socket

.connection_error_send_result_len:
    ; Handle error sending result length
    jmp .cleanup_socket

.connection_error_send_result:
    ; Handle error sending result data
    jmp .cleanup_socket

.cleanup_socket:
    push dword [esi]
    call close
    add esp, 4

.cleanup:
    push dword [client_address+3]
    push dword [client_address+2]
    push dword [client_address+1]
    push dword [client_address+0]
    push msg_connection_closed
    call printf
    add esp, 16

    pop ebp
    pop edi
    pop esi
    pop ebx
    pop ebp
    ret

; Helper function to receive a specific number of bytes
receive_all:
    push ebp
    mov ebp, esp
    mov edi, [ebp+8] ; Buffer
    mov esi, [ebp+12] ; Socket
    mov ecx, [expected_bytes] ; Number of bytes to receive
    xor eax, eax ; Total bytes received

.receive_loop:
    cmp eax, ecx
    jge .receive_done
    push ecx
    sub ecx, eax ; Remaining bytes
    cmp ecx, word [chunk_size]
    jle .receive_chunk_size
    mov ecx, word [chunk_size]
.receive_chunk_size:
    push ecx
    push esi
    push edi
    call recv
    add esp, 12
    cmp eax, 0
    jle .receive_error ; Connection closed
    add edi, eax
    add eax, [ebp-4] ; Add to total received
    mov [ebp-4], eax
    pop ecx
    jmp .receive_loop

.receive_done:
    mov eax, [ebp-4] ; Return total bytes received
    jmp .receive_exit

.receive_error:
    mov eax, -1
    jmp .receive_exit

.receive_exit:
    mov esp, ebp
    pop ebp
    ret

section .bss
    operation_code_buffer resb 1
    num_dimensions_buffer resb 4
    num_fx_buffer resb 4
    num_fy


No comments: