gphoto / libgphoto2

The libgphoto2 camera access and control library.
GNU Lesser General Public License v2.1
991 stars 317 forks source link

Socket error after gp_camera_exit in windows/msys2 #885

Closed jensanjo closed 1 year ago

jensanjo commented 1 year ago

This issue was originally reported at python-gphoto2 issue 152 The problem

After initializing the camera and then calling gp_camera_exit an erroroccurs when i create a socket.

System OS: Windows 10 + MSYS2 MingW 64-bit Python 3.8 libgphoto2-2.5.27 python-gphoto2 2.3.4 camera: Canon EOS 1200D

To Reproduce

Example program

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <gphoto2/gphoto2-camera.h>
#include <winsock2.h>

static void check_socket(SOCKET sock) {
    if (sock == INVALID_SOCKET)
    {
        printf("Errro creating socket: %ld\n", WSAGetLastError());
        WSACleanup();
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    printf("Hello world");
    WSADATA wsaData;
    int res;

    res = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (res != 0) {
        printf("WSAStartup failed: %d\n", res);
        exit(EXIT_FAILURE);
    }

    SOCKET sock;

    printf("Create first socket: ");
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    check_socket(sock);
    printf("OK\n");

    printf("Initialize camera\n");
    Camera *camera;
    assert(GP_OK == gp_camera_new(&camera));
    assert(GP_OK == gp_camera_init(camera, NULL));
    printf("Exit camera\n");
    assert(GP_OK == gp_camera_exit(camera, NULL));

    printf("Create second socket: ");
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    check_socket(sock);
    printf("OK\n");

    return 0;
}

Output

$ ./camtest.exe
Create first socket: OK
Initialize camera
Exit camera
Create second socket: Errro creating socket: 10093
jensanjo commented 1 year ago

I found the problem in camlibs/ptp2/library.c. The WSAStartup is called in camera_init, but only if the camera port type is GP_PORT_PTPIP:

    case GP_PORT_PTPIP: {
        GPPortInfo  info;
        char        *xpath;

#if defined(HAVE_LIBWS232) && defined(WIN32)
        WORD wsaVersionWanted = MAKEWORD(1, 1);
        WSADATA wsaData;
        if (WSAStartup(wsaVersionWanted, &wsaData)) {
            GP_LOG_E("WSAStartup failed.");
            return GP_ERROR;
        }
#endif

In camera_exit WSACleanup is called, but in this only if the port type is NOT GP_PORT_PTPIP, which is obviously not what was intended. Since my port type is GP_PORT_USB the WSAStartup is not called, but the WSACleanup is.

#if defined(HAVE_LIBWS232) && defined(WIN32)
    else if ((camera->port!=NULL) && camera->port->type != GP_PORT_PTPIP) {
        WSACleanup();
    }
#endif