mmozeiko
My main suggestion would be to NOT do simple wrapper around BSD sockets. Do a bit more. Create all API nonblocking/async. Most difficult part will be dns resolving. On Win32 it is built in, but on Linux you'll need to do more code (don't use GNU libc specific functions, so it is portable). Allow user to do sync requests by explicit wait function, and/or what ratchetfreak suggests - integrate with gui event loop. Don't do high level functions ("send object position"), allow to send/receive raw bytes.
For *nix my plan is to implement everything in POSIX standard functions without using any extensions, but i expect that there will be differences between win32, linux and unix.
Regarding blocking vs non-blocking. I am not sure what the best way is. Normally i want the caller to decide how to use it.
I think having two apis: Blocking and Non-Blocking would be most suitable. Non-blocking would be handled on separated threads with bare minimum cache structures and blocking will most likely be just a wrapper around network functions.
And there will be no high-level functions such as "send object position". But there will be functions for sending/receiving raw bytes and integral data-types such as int16_t, uint32_t, etc. and maybe two functions for sending/receiving UTF-8 strings + conversion functions from system byte-order to network-byte order and vice versa.
A few examples (Blocking):
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 | // Does not do any byte-order conversion
// Data wont be send in multiple packets. When it does not fit it will be cut of.
size_t fplSocketReadRaw(const fplSocket *socket, const size_t size, uint8_t *targetBuffer);
size_t fplSocketWriteRaw(const fplSocket *socket, const size_t size, const uint8_t *sourceBuffer);
// Does not do any byte-order conversion
// Bytes will be send/received in multiple packets if needed (Datagram limitation)
// Appends a header automatically, so you dont have to deal with limitations
size_t fplSocketReadBytes(const fplSocket *socket, const size_t size, uint8_t *targetBuffer);
size_t fplSocketWriteBytes(const fplSocket *socket, const size_t size, const uint8_t *sourceBuffer);
// Does byte-order conversion automatically
int16_t fplSocketReadS16(const fplSocket *socket);
int32_t fplSocketReadS32(const fplSocket *socket);
// Does byte-order conversion automatically
size_t fplSocketWriteS16(fplSocket *socket, const int16_t value);
size_t fplSocketWriteS32(fplSocket *socket, const int16_t value);
// Does byte-order conversion automatically
size_t fplSocketWriteS16(fplSocket *socket, const int16_t value);
size_t fplSocketWriteS32(fplSocket *socket, const int16_t value);
// Does byte-order conversion automatically (Wide <-> UTF-8)
// String will be send/received in multiple packets if needed (Datagram limitation)
size_t fpSocketWriteString(fplSocket *socket, const char *source, const size_t sourceLen);
size_t fplSocketReadString(fplSocket *socket, const char *maxTargetLen, char *target);
// Resolving / Lookup
bool fplResolveIPAddressV4ByHostname(const char *inHostname, fplNetworkIPAddressV4 *outAddress);
bool fplResolveIPAddressV6ByHostname(const char *inHostname, fplNetworkIPAddressV6 *outAddress);
bool fplResolveHostnameByIPAddressV4(const fplNetworkIPAddressV4 *inAddress, const size_t maxOutHostnameLen, char *outHostname);
bool fplResolveHostnameByIPAddressV6(const fplNetworkIPAddressV6 *inAddress, const size_t maxOutHostnameLen, char *outHostname);
// Better resolving / lookup
typedef enum fplNetworkIPAddressType {
fplNetworkIPAddressType_V4 = 0,
fplNetworkIPAddressType_V6,
} fplNetworkIPAddressType;
typedef struct fplNetworkIPAddress {
union {
char[32] v4;
char[128] v6;
};
fplNetworkIPAddressType type;
} fplNetworkIPAddress;
bool fplParseIPAddress(const char *source, const size_t sourceLen, fplNetworkIPAddress *outAddress);
bool fplResolveIPAddressByHostname(const char *inHostname, fplNetworkIPAddress *outAddress);
bool fplResolveHostnameByIPAddress(const fplNetworkIPAddress *inAddress, const size_t maxOutHostnameLen, char *outHostname);
|
ratchetfreak
The network events notification must be able to integrate seamlessly into the gui event notification. However it should also be possible to make another thread deal with the result.
Something like continuation queue is a good choice, with each command you also pass the queue that you want notified when the operation is done. With option to make it a GUI event or wait right then and there.
At the moment the window event system in blocking only, so integrating network events would not work for time-critical events such as receiving data, but it could optionally support one-time events such as connecting/disconnecting events. But i dont want to add a full caching queue. The caller should be responsible for that.
The only thing cached should be just the connection state with socket/hostname/ip-address informations.