Writing to socket fails with the addition of any single line of code to c program

0

I'm writing a c program designed to transfer data over a socket to python client. I've encountered a really strange issue where writing to the created socket stops working with the addition of virtually any line of code after a certain point in the program.

To expand on the issue: I'm trying to write an arbitrary number to the socket, e.g. 256. This works fine, i.e. the python client receives the number 256 from the c server, as long as there aren't any commands beyond get_status(s2mm_status,"S2MM"); If there are any such commands beyond this point, the "0" gets written to the socket instead of whatever number (e.g. 256) I've specified. Anything as simple as the declaration "int i" results in this behavior.

Needless to say, I'm confused. I'm wondering if I'm using too much memory or something? I just don't know how to diagnose the problem. Anyway, I've provided the code below. Sorry about the length, I just really don't know what is or is not relevant.

To provide a basic explanation of the code: a number of memory maps are created so that I can write specific values to registers, which initiates the recording of data from an ADC aboard the device, writing of this data to memory, and then passing this data over a socket to the python client.

#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h>
#include<sys/socket.h> 
#include<arpa/inet.h> // inet_addr 
#include<unistd.h> //write 
#include<pthread.h> //for threading, link with lpthread 
#include<sys/mman.h>
#include <fcntl.h>
#include <arpa/inet.h> //https://linux.die.net/man/3/htonl
#include <time.h> 
#include<math.h> 

#include "server_library.h" 

/*********************************/
//Address Editor                         
/*********************************/
//ps_0 
//  Data 
//      axi_dma_0 S_AXI_LITE reg 0x4040_0000 64K 0x4040_FFFF
//axi_dma_0
//  Data_SG 
//      ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
//  DATA_MM2S
//      ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
//  DATA_S2MM
//      ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
/*********************************/

/*********************************/
//Addresses                        
/*********************************/
#define AXI_DMA_ADDRESS         0x40400000
#define HP0_ADDRESS             0x08000000 //Formerly HP0_DMA_BUFFER_MEM_ADDRESS
#define MM2S_BASE_DESC_ADDR     HP0_ADDRESS //Formerly HP0_MM2S_DMA_DESCRIPTORS_ADDRESS
#define S2MM_BASE_DESC_ADDR     HP0_ADDRESS+MEMBLOCK_WIDTH+1 //Formerly HP0_S2MM_DMA_DESCRIPTORS_ADDRESS
#define MM2S_SOURCE_ADDRESS     HP0_ADDRESS+SG_DMA_DESCRIPTORS_WIDTH+1 //Formerly HP0_MM2S_SOURCE_MEM_ADDRESS
#define S2MM_TARGET_ADDRESS     HP0_ADDRESS+(MEMBLOCK_WIDTH+1)+SG_DMA_DESCRIPTORS_WIDTH+1 //Formerly HP0_S2MM_TARGET_MEM_ADDRESS

// AXI_DMA_ADDRESS: 0x40400000
// HP0_ADDRESS: 0x08000000
// MM2S_BASE_DESC_ADDR: 0x08000000
// S2MM_BASE_DESC_ADDR: 0x0c000000
// MM2S_SOURCE_ADDRESS: 0x08010000
// S2MM_TARGET_ADDRESS: 0x0c010000

/*********************************/
//Miscellaneous                         
/*********************************/
#define DESCRIPTOR_REGISTERS_SIZE 0xFFFF
#define SG_DMA_DESCRIPTORS_WIDTH 0xFFFF 
#define MEMBLOCK_WIDTH 0x3FFFFFF //Size of memory used by S2MM and MM2S 
#define BUFFER_BLOCK_WIDTH 0x7D0000 //Size of memory block per descriptor in bytes 
#define NUM_OF_DESCRIPTORS 0x02 //Number of descriptors for each direction 

#define START_FRAME     0x08000000 //TXSOF = 1 TXEOF = 0 
#define MID_FRAME       0x00000000 //TXSOF = TXEOF = 0 
#define COMPLETE_FRAME  0x0C000000 //TXSOF = TXEOF = 1
#define END_FRAME       0x04000000 //TXSOF = 0 TXEOF = 1

#define CYCLIC_ENABLE   0x10

#define TRANSFER_BYTES 1024
#define TRANSFER_INTS 256 
#define TRANSFER_BITS 8*TRANSFER_BYTES  
#define N_DESC 2


/*********************************/
//Offsets                          
/*********************************/
// MM2S CONTROL
#define MM2S_CONTROL_REGISTER       0x00    // MM2S_DMACR
#define MM2S_STATUS_REGISTER        0x04    // MM2S_DMASR
#define MM2S_CURDESC                0x08    // must align 0x40 addresses
#define MM2S_CURDESC_MSB            0x0C    // unused with 32bit addresses
#define MM2S_TAILDESC               0x10    // must align 0x40 addresses
#define MM2S_TAILDESC_MSB           0x14    // unused with 32bit addresses

#define SG_CTL                      0x2C    // CACHE CONTROL

// S2MM CONTROL
#define S2MM_CONTROL_REGISTER       0x30    // S2MM_DMACR
#define S2MM_STATUS_REGISTER        0x34    // S2MM_DMASR
#define S2MM_CURDESC                0x38    // must align 0x40 addresses
#define S2MM_CURDESC_MSB            0x3C    // unused with 32bit addresses
#define S2MM_TAILDESC               0x40    // must align 0x40 addresses
#define S2MM_TAILDESC_MSB           0x44    // unused with 32bit addresses

//Scatter/Gather Control 
#define NEXT_DESC   0x00 //Set to address of next descriptor in chain 
#define BUFF_ADDR   0x08 //Set to address to read from (MM2S) or write to (S2MM) 
#define CONTROL     0x18 //Set transfer length, T/RXSOF and T/RXEOF 
#define STATUS      0x1C //Descriptor status

/*********************************/
//Functions                         
/*********************************/
unsigned int set_offset(unsigned int* virtual_address, int offset, unsigned int value){
    virtual_address[offset>>2] = value; 
}

unsigned int get_offset(unsigned int* virtual_address, int offset) {    
    return virtual_address[offset>>2];
}

void print_offset(unsigned int* virtual_address, int offset){    
    unsigned int value = get_offset(virtual_address,offset); 
    printf("0x%08x\n",value); 
}

void memsend(void* virtual_address, int byte_count, int socket_desc)
{
    unsigned int *p = virtual_address;
    int offset; 
    for(offset = 0; offset<byte_count;offset++){
        printf("0x%08x\n",p[offset]); 
        write(socket_desc,&p[offset],sizeof(p[offset])); 
    }
}

void memdump(void* virtual_address, int byte_count)
{    
    unsigned int *p = virtual_address;
    int offset; 
    for(offset = 0; offset<byte_count;offset++){
        printf("%d: 0x%08x\n",offset,p[offset]);         
    }
}

void get_status(uint32_t status, char *type){   
    if(type == "S2MM"){
        printf("S2MM status 0x%08x @0x%08x\n",status,AXI_DMA_ADDRESS+S2MM_STATUS_REGISTER);         
    }
    if(type == "MM2S"){
        printf("MM2S status 0x%08x @0x%08x\n",status,AXI_DMA_ADDRESS+MM2S_STATUS_REGISTER);         
    }
    if(status & 0x00000001) printf(" Halted"); 
    if(status & 0x00000002) printf(" Idle"); 
    if(status & 0x00000008) printf(" SGIncld"); 
    if(status & 0x00000010) printf(" DMAIntErr"); 
    if(status & 0x00000020) printf(" DMASlvErr"); 
    if(status & 0x00000040) printf(" DMADecErr"); 
    if(status & 0x00000100) printf(" SGIntErr"); 
    if(status & 0x00000200) printf(" SGSlvErr"); 
    if(status & 0x00000400) printf(" SGDecErr"); 
    if(status & 0x00001000) printf(" IOC_Irq"); 
    if(status & 0x00002000) printf(" Dly_Irq"); 
    if(status & 0x00004000) printf(" Err_Irq"); 
    else printf(" running"); 
    printf("\n"); 
}


int main(){

    int mm2s_status, s2mm_status;       
    uint32_t mm2s_base_descriptor_address; //Formerly mm2s_current_descriptor_address
    uint32_t s2mm_base_descriptor_address; //Formerly s2mm_current_descriptor_address
    uint32_t mm2s_tail_descriptor_address;
    uint32_t s2mm_tail_descriptor_address;
    int fd = open("/dev/mem",O_RDWR|O_SYNC);    
    //Create 64K AXI DMA Memory Map at AXI_DMA_ADDRESS (0x40400000)
    unsigned int* axi_dma = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,AXI_DMA_ADDRESS); 
    //Create 64k mm2s descriptors memory map at HP0_MM2S_DMA_DESCRIPTORS_ADDRESS (0x08000000)
    unsigned int* mm2s_descriptors = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,MM2S_BASE_DESC_ADDR); //Formerly mm2s_descriptor_register_mmap
    //Create 64k s2mm descriptors memory map at HP0_S2MM_DMA_DESCRIPTORS_ADDRESS (0x0c000000)
    unsigned int* s2mm_descriptors = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,S2MM_BASE_DESC_ADDR); //Formerly s2mm_descriptor_register_mmap
    //Create ~1Mb x Num_Descriptors source memory map at HP0_MM2S_SOURCE_MEM_ADDRESS  (0x08010000)
    unsigned int* source_memory = mmap(NULL,BUFFER_BLOCK_WIDTH*NUM_OF_DESCRIPTORS,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(off_t)(MM2S_SOURCE_ADDRESS)); //Formerly source_mmap
    //Create ~1Mb x Num_Descriptors target memory map at HP0_S2MM_TARGET_MEM_ADDRESS (0x0c010000)
    unsigned int* dest_memory = mmap(NULL,BUFFER_BLOCK_WIDTH*NUM_OF_DESCRIPTORS,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(off_t)(S2MM_TARGET_ADDRESS)); //Formerly dest_mmap 

    //Clear mm2s descriptors 
    memset(mm2s_descriptors,0x00000000,DESCRIPTOR_REGISTERS_SIZE); 
    //Clear s2mm descriptors 
    memset(s2mm_descriptors,0x00000000,DESCRIPTOR_REGISTERS_SIZE); 
    //Clear Target Memory 
    memset(dest_memory,0x00000000,NUM_OF_DESCRIPTORS*BUFFER_BLOCK_WIDTH/4); 

        //Reset and halt all DMA operations 
    set_offset(axi_dma,MM2S_CONTROL_REGISTER,0x4); 
    set_offset(axi_dma,S2MM_CONTROL_REGISTER,0x4); 
    set_offset(axi_dma,MM2S_CONTROL_REGISTER,0x0); 
    set_offset(axi_dma,S2MM_CONTROL_REGISTER,0x0); 
    mm2s_status = get_offset(axi_dma,MM2S_STATUS_REGISTER); 
    s2mm_status = get_offset(axi_dma,S2MM_STATUS_REGISTER); 
    get_status(mm2s_status,"MM2S"); 
    get_status(s2mm_status,"S2MM"); 

    /*********************************************************************/
    // Any code after this point, save for a print function, 
    // breaks the write function (line 223) below. 
    //Specifically, it goes from correctly writing TRANSFER_INTS = 256 
    //to writing 0 to "new_socket"
    //????
    /*********************************************************************/


    /*********************************************************************/
    // Open a server 
    /*********************************************************************/
    //Define variables 
    int new_socket,c; 
    int socket_desc; 
    struct sockaddr_in created_server_addr, client_addr; 
    //Create Socket 
    socket_desc = open_socket(socket_desc); 
    //Create Server 
    created_server_addr = server_structure(created_server_addr); 
    //Bind Socket 
    bind_socket(socket_desc,created_server_addr); 
    //Listen
    listen(socket_desc,3); 
    puts("Waiting for incoming connections..."); 
    //Transfer Data over socket 
    while(new_socket=accept(socket_desc,(struct sockaddr *)&client_addr, (socklen_t*)&c))
    {
        puts("Connection Accepted.\n"); 
        printf("Transfer Size: %d\n",TRANSFER_INTS);
        uint32_t htonl_TRANSFER_INTS = htonl(TRANSFER_INTS);  
        write(new_socket, &htonl_TRANSFER_INTS,sizeof(htonl_TRANSFER_INTS));    
        printf("Write Data (Destination memory block): \n"); 
        close(new_socket); 
        break; 
    }
    close(socket_desc); 
    /*********************************************************************/
}

I'm also including the "server_library.h" file for reference, which I wrote ti simplify the process of starting a socket a little bit. I can provide the python client code on request, but I'm already worried this is way too much code to sift through already.

#ifndef MY_HEADER_H
#define MY_HEADER_H 

//Start/open Socket 
int open_socket(int socket_desc)
{
    int option = 1; 
    socket_desc = socket(AF_INET,SOCK_STREAM,0); 
    if(socket_desc == -1)
    {
        printf("Could not create socket\n"); 
    }
    //This stupid line fixes binds failing 
    setsockopt(socket_desc,SOL_SOCKET,SO_REUSEADDR,(void *)&option,sizeof(option)); 
    return socket_desc; 
}
//Prepare server structure 
struct sockaddr_in server_structure(struct sockaddr_in server_addr)
{
    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = INADDR_ANY; 
    server_addr.sin_port = htons(8888); 
    return server_addr; 
}
//Bind Socket
void bind_socket(int socket_desc, struct sockaddr_in server_addr)
{

    if(bind(socket_desc,(struct sockaddr *)&server_addr, sizeof(server_addr))<0)
    {
        puts("Bind Failed\n"); 
    }else{
        puts("Bind Done\n"); 
    }

}

//Send Message (uint32_t)
//Doesn't Work I dunno why 
void send_int(uint32_t message, int socket) 
{
    message = htonl(message);
    write(socket, &message, sizeof(message)); 
}


#endif 

I'm sorry to be so vague here and throw so much code out, I just don't even really have any ideas for how to diagnose this issue, let alone start narrowing the cause down.

Anyway, thank you for the help. I'm happy to provide as much additional information as I am able.

c
sockets
memory
embedded
asked on Stack Overflow Nov 5, 2018 by GeneralPancake • edited Nov 6, 2018 by GeneralPancake

1 Answer

0

When changing the code in unrelated ways breaks a program, here are some things to check for: 1. Stack overflow (this is more common in firmware/embedded code on microprocessors, but can happen especially with recursion or if you put large arrays and such on the stack) 2. Wild pointers, out-of-bounds writes to arrays or strings, etc. which lead to a memory overwrite (changing the code in an unrelated way may change the memory layout such that the memory overwrite is in either a harmless or a harmful location) [Do you check that all the arrays you try to allocate are successfully allocated?] [uses of set_offset are candidates for out-of-bounds access]

That is where I would start.

And, of course, turning on compiler warnings and checking return values from all function calls that have them.

If you do all of the above, you will either find the bug, or you can give us information which will help us to help you better.

answered on Stack Overflow Nov 6, 2018 by Basya

User contributions licensed under CC BY-SA 3.0