Click here to Skip to main content
14,607,026 members
Rate this:
Please Sign up or sign in to vote.
Hi There's a source (camera) which sends notifications (motion alarms) to port 8085 of a server I've subscribed its IP for it. Maybe in such a negotiation I can't call it 'server', but it's our server which serves some other things.
I've written two programs for receiving and echoing current motion status, for now only on screen. Packets which are received are in shape of XML which I may parse and find the required info. For testing, I just extract times which are labeled UtcTime. Another machine subscribed itself to the same camera by using Onvif Device Manager, so that I may check whether I miss some 'times'. One of these programs are in GoLang and one is in C++. The former one works as expected while the latter one doesn't. Maybe this one (C++) has been my first experience in socket programming. I didn't use any additional library while in C++ and I used the traditional socket programming method not to be required to use any additional library at customer site too. The problem is that ODM echos new times (or say notification messages) as well as the GoLang code while the C++ code sticks at accept function (accepting... message). I give you both for investigation.

Notes:

1. accept function sticks and I terminate the program by Ctrl+C. The next time I run the program (C++) I get the packets I couldn't get before!
2. OS is Linux (Ubuntu 12.04). The GoLang code works in the same OS.

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

func count() (f func() int) {
	var counter int
	f = func() int {
		counter++
		return counter
	}
	return
}

func main() {
	http.HandleFunc("/", Server)
	http.ListenAndServe(":8085", nil)
}

func Server(w http.ResponseWriter, r *http.Request) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}
	str := string(body)
	for {
		index := strings.Index(str, "UtcTime")
		if index == -1 {
			break
		}
		part := str[index+20 : index+28]
		fmt.Printf("%s\n", part)
		str = str[index+28:]
	}
}

This was the code in GoLang which works properly. Now the C++ code which doesn't work as expected and sticks on accepting...:
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string>

#define DBG printf("%s:%d\n", __FILE__, __LINE__)
#define DIE die(__FILE__, __LINE__)

void die(const char *file, int line)
{
    printf("%s:%d: %s\n", file, line, strerror(errno));
    exit(1);
}

std::string extractTime(const char *utc)
{
    char buf[80];
    memcpy(buf, utc + 11, 8);
    buf[9] = 0;
    return buf;
}

int main()
{
    printf("creating socket...\n");
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1)
        DIE;
    int reuseaddr = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1)
        DIE;

    printf("binding...\n");
    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8085);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(sock, (sockaddr *)&addr, sizeof(addr)) == -1)
        DIE;

    printf("listening...\n");
    if (listen(sock, SOMAXCONN) == -1)
        DIE;
    socklen_t size = sizeof(addr);
    while (true)
    {
        printf("accepting...\n");
        int new_sock = accept(sock, 0, 0);
        if (new_sock < 0)
            DIE;
        const int buf_size = 80;
        char buf[buf_size * 2 + 1];
        int read_size;
        std::string time;
        while (true)
        {
            memcpy(buf, buf + buf_size, buf_size);
            read_size = recv(new_sock, buf + buf_size, buf_size, 0);
            if (read_size < 0)
                DIE;
            buf[buf_size + read_size] = 0;
            char *p = strstr(buf, "UtcTime");
            if (p && (p - buf < buf_size))
            {
                char buf2[80];
                char *p2 = strstr(p + 9, "\"");
                if (p2)
                {
                    memcpy(buf2, p + 9, p2 - p - 9);
                    buf2[p2 - p - 9] = 0;
                    time = extractTime(buf2);
                    printf("%s\n", time.c_str());
                }
            }
            if (strstr(buf, "</SOAP-ENV:Envelope>"))
                break;
        }
    }
    return 0;
}


What I have tried:

First, I thought it might be because I don't receive the whole block by a single recv function. For this, I allocated a 80K block to be large enough to hold the whole received notification. But the behavior didn't change. Then I thought it might be because I call recv in main thread while the other notification messages are ready and in the time I should process them I go to recv the previous one. For this, I moved recv to a separate process (by fork), but it didn't help.
Posted
Comments
Richard MacCutchan 9-Jan-20 7:38am
   
You will need to use your debugger to find out why the accept is never being activated when the client sends it a message.
ilostmyid2 10-Jan-20 1:11am
   
to debug inside accept assembly code?!
Richard MacCutchan 10-Jan-20 5:05am
   
Debugging at source level is usually enough. But only you can create the exact environment that this code runs in, so only you can do the debugging.
ilostmyid2 10-Jan-20 6:27am
   
Have no idea. The code is in front of you. It just sticks at accept. What can I do? The code above it runs without any problem. What to debug?!
Richard MacCutchan 10-Jan-20 6:52am
   
Yes, the code is in front of me, but it does not tell me anything. As I said before, we cannot debug this code because we do not have the environment to test it.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100