[C++] Mingw & open()

Pagina: 1
Acties:

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Ik ben met wat file-gerelateerde zaken bezig, en liep tegen het volgende aan:

Ik gebruik een template om exception-safe met filehandles te kunnen werken:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
template <int flags = O_RDONLY, int mode = (S_IRUSR|S_IWUSR)>
class FileGuard
{
private:
    int hFileHandle;
public:
    FileGuard(const char *filename)
        : hFileHandle(::open(filename, flags, mode))
    {
        if(hFileHandle < 0)
            THROW_EXCEPTION(IOException, OSFileOpen);
    }
    
    ~FileGuard()
    {
        if(hFileHandle >= 0) close();
    }
    
    void close()
    {
        if(hFileHandle < 0)
            THROW_EXCEPTION(IOException, OSFileClosed);
            
        if(::close(hFileHandle) != 0)
            THROW_EXCEPTION(IOException, OSFileCloseError);
        
        hFileHandle = -1;
    }
    
    operator int() const
    {
        return hFileHandle;
    }
};


Als ik nu met
C++:
1
FileGuard<O_WRONLY | O_CREAT> test("test.txt");

een bestand probeer te openen dat niet bestaat, krijg ik geen filehandle (oftewel: THROW_EXCEPTION(IOException, OSFileOpen); wordt uigevoerd). Als het bestand wel bestaat, krijg ik netjes een filehandle terug.

Conform de specs moet O_CREAT (specs hier) ervoor zorgen dat het bestand wordt gecreerd.

Ik werk op deze testmachine als administrator, dus het ligt niet aan mijn rechten.
De c-style 'errno' variabele geeft EINVAL terug.

Ik programmeer met Dev-Cpp, en compileer op MingW32.

[ Voor 3% gewijzigd door B-Man op 23-08-2004 19:38 ]


  • B-Man
  • Registratie: Februari 2000
  • Niet online
Hmmm, ik heb er nu
C++:
1
FileGuard<O_WRONLY | O_CREAT | O_EXCL> test("test.txt");

van gemaakt, en nu werkt het wel (test.txt wordt nu als het nog niet bestaat wel aangemaakt).

Toch de specs er nog maar eens op naslaan.

[ Voor 7% gewijzigd door B-Man op 23-08-2004 20:32 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Je bent de copy ctor en de assignment operator vergeten.
Ten tweede gebruikt MinGW de Microsoft C library, en die kent blijkbaar geen S_IRUSR|S_IWUSR. Ook op andere punten zal deze lib afwijken van POSIX - bijvoorbeeld "/" is niet de file system root.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23-05 18:13
Het heeft niet zoveel met je oorspronkelijke probleem te maken, maar waarom wil je eigenlijk die flags en mode parametriseren? Dat lijken mij nu typisch waarden die je aan de constructor meegeeft.

Op deze manier moet je alle functies die een FileGuard als argument krijgen, alle klassen die een FileGuard als member variable hebben, enzovoorts, parametriseren. Wat een onnodige ellende!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-05 23:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een exception gooien in een destructor is trouwens niet erg handig (close kan een exception gooien, en die wordt vanuit de destructor aangeroepen). Dit in verband met stack unwinding als er al een exception gegooid wordt.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • B-Man
  • Registratie: Februari 2000
  • Niet online
.oisyn schreef op 24 augustus 2004 @ 15:39:
Een exception gooien in een destructor is trouwens niet erg handig (close kan een exception gooien, en die wordt vanuit de destructor aangeroepen). Dit in verband met stack unwinding als er al een exception gegooid wordt.
Ja, daar was ik inmiddels ook al achter. De Winsock API knalt er dan lekker uit met een "abnormal program termination" error.
Dat heb ik opgelost door een try-catch block om de aanroep naar close().

Ik zit inmiddels met een ander probleem. Ik ben mijn eigen classes wat aan het testen, en onder windows krijg ik na een geldige accept() netjes een SOCKET terug, maar ik kan er niets mee. Zo geeft closesocket() bijvoorbeeld een WSAENOTSOCK error. Ik zie ook niet waar het probleem zit, want ik doe alles netjes volgens de specs.

Zo zou ik in onderstaande accept() functie gewoon in staat moeten zijn om het net geaccepteerde socket meteen weer te sluiten, maar dat gaat dus niet.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
template<typename SocketType>
class SocketListen
{
...
public:
    void listen(int type, const char *address, int port = 0)
    {
        if(fd != -1)    THROW_EXCEPTION(IOException, AlreadyOpen)
        
        Socket::setup();
        
        int domain = 0;
        SocketAddress addr;
        int addr_len = 0;
        SocketStream::lookup(addr, domain, type, address, port, addr_len);

        fd = ::socket(domain, SOCK_STREAM, 0); // OS chooses protocol
        if(fd == -1)    THROW_EXCEPTION(IOException, InvalidFileDescriptor)
        #ifdef PLATFORM_WIN32
        if(fd == INVALID_SOCKET)
            THROW_EXCEPTION(IOException, InvalidFileDescriptor)
        #endif
        
        // Allow reuse
        int option = true;
        if(::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&option, sizeof(option)) == -1)
            THROW_EXCEPTION(IOException, InvalidFileDescriptor)
            
        if(::bind(fd, &addr.generic, addr_len) == -1
         || ::listen(fd, backlog) == -1)
        {
            Socket::close(fd);
            fd = -1;
            THROW_EXCEPTION(IOException, CannotListen)
        }
        
        printf("SocketListen::listen() fd=%d\n", fd);
    }
    
    std::auto_ptr<SocketType> accept(int timeout = Stream::InfiniteTimeout)
    {
        if(fd == -1)    THROW_EXCEPTION(IOException, InvalidFileDescriptor)
        
        unsigned int sock;
        struct sockaddr addr;
        socklen_t addrlen = sizeof(addr);
        {
            struct timeval s_timeout;
            fd_set inp;
            FD_ZERO(&inp);
            FD_SET(fd, &inp);
            
            if(timeout == Stream::InfiniteTimeout)
            {
                s_timeout.tv_sec    = 0;
                s_timeout.tv_usec   = 0;
            }
            else
            {
                s_timeout.tv_sec    = timeout / 1000;
                s_timeout.tv_usec   = (timeout % 1000) * 1000;
            }
            
            // select()
            switch(::select(1, &inp, 0, 0, &s_timeout))
            {
            case -1:
                // We were interrupted
                if(errno == EINTR) return std::auto_ptr<SocketType>();
                else THROW_EXCEPTION(IOException, OSFileReadError)
                break;
            case 0:
                // No data, must be a timeout
                return std::auto_ptr<SocketType>();
                break;
            default:
                // Data is available, continue
                break;
            }
            
            //sock == ::accept(fd, &addr, &addrlen);
            sock == ::accept(fd, NULL, NULL);
            
            printf("SocketListen::accept() (fd=%d)\n", sock);
        }
        
        if(sock == -1)
            THROW_EXCEPTION(IOException, AcceptError)
        #ifdef PLATFORM_WIN32
        if(sock == INVALID_SOCKET)
            THROW_EXCEPTION(IOException, AcceptError)
        #endif
        /*
        printf("Hmmm, so let's try to close it right @ accept time\n");
        if(::closesocket(sock) == SOCKET_ERROR)
            printf("... Could not close it: %s\n", WSAGetLastError());
        else
            printf("... Here we CAN close it?\n");
        */
            
        // Return this new socket
        return std::auto_ptr<SocketType>(new SocketType(sock));
    }
};

[ Voor 4% gewijzigd door B-Man op 27-08-2004 14:44 ]


Verwijderd

Volgens mij retourneert de winsock versie van accept() een SOCKET en geen integer, kan het niet zijn dat dat de fout verorzaakt?

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Verwijderd schreef op 27 augustus 2004 @ 15:02:
Volgens mij retourneert de winsock versie van accept() een SOCKET en geen integer, kan het niet zijn dat dat de fout verorzaakt?
De andere sockets waar ik mee werk (zo ook de luisterende socket) "behandel" ik ook gewoon als een integer.

Volgens de winsock2.h header die bij MINGW32 zit is het een unsigned int:
C++:
1
2
typedef unsigned int    u_int;
typedef u_int   SOCKET;


De filedescriptor die ik van accept terugkrijg is trouwens '1271232'.

Zoals je ziet gebruik ik trouwens een unsigned int, net zoals de winsock header, dus dat zou het probleem niet mogen zijn.

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Pffff, slaapkop :D (ik dus haha).

C++:
1
sock == ::accept(fd, NULL, NULL);


'==', dat kan nooit goed gaan he ;)

Toch wat te laat gemaakt vannacht.

Verwijderd

B-Man schreef op 27 augustus 2004 @ 15:19:
Pffff, slaapkop :D (ik dus haha).

C++:
1
sock == ::accept(fd, NULL, NULL);


'==', dat kan nooit goed gaan he ;)

Toch wat te laat gemaakt vannacht.
Mja ik heb er ook overheen gelezen, maar ik zoek normaal niet eens naar dit soort fouten; de compiler haalt ze er voor me uit (met optie -Wall krijg je een "warning: value computed is not used").

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Verwijderd schreef op 27 augustus 2004 @ 16:08:
[...]


Mja ik heb er ook overheen gelezen, maar ik zoek normaal niet eens naar dit soort fouten; de compiler haalt ze er voor me uit (met optie -Wall krijg je een "warning: value computed is not used").
Hmmm, dan zal ik dat hier ook eens aanzetten.

[ Voor 31% gewijzigd door B-Man op 27-08-2004 21:34 . Reden: *is sufferd ]

Pagina: 1