How to know data size in UDP?

Hello, I'm trying to implement DNS resolver without any external C libraries for my daemon program which uses DNS lookup. I know the "hsdns" library exists. But since it calls GNU asynchronous DNS resolver library by FFI, all threads of Haskell are blocked on non-threaded RTS. If the threaded RTS is used, forkProcess kills the IO thread. With the threaded RTS of at least GHC 6.10.4, we cannot make our program as a daemon nor use pre-fork mechanism. Thus, I decided to implement DNS resolver only with non-blocking Haskell functions. I use a *connected* UDP socket like this: proto <- getProtocolNumber "udp" let hints = defaultHints { addrFlags = [AI_ADDRCONFIG, AI_NUMERICHOST, AI_PASSIVE] , addrSocketType = Datagram , addrProtocol = proto } a:_ <- getAddrInfo (Just hints) (Just "An IP address of DNS server") (Just "domain") sock <- socket (addrFamily a) (addrSocketType a) (addrProtocol a) connect sock (addrAddress a) h <- socketToHandle sock ReadWriteMode hSetBuffering h NoBuffering hSetBinaryMode h True If my understating is correct, I cannot use recvFrom since it calls recvfrom() with FFI. So, I use socketToHandle to translate a socket to a handle. Since the handle is associated with UDP, the entire data size should be known when a UDP packet arrived. But I cannot find a way to know data size. (I want a function like hFileSize.) Note that hGetContents blocks. Without data size in advance, a program to handle network protocols on UDP becomes quite dirty or sometime cannot be implemented. So, please tell me how to know data size associated with a handler of UDP? --Kazu

On Oct 29, 2009, at 04:31 , Kazu Yamamoto (山本和彦) wrote:
Since the handle is associated with UDP, the entire data size should be known when a UDP packet arrived. But I cannot find a way to know data size. (I want a function like hFileSize.) Note that hGetContents blocks.
The short answer is: you can't. You need to find a way to make recv() work. Longer: read() is intended for streams. If you read() a datagram socket you may get a single packet or the system may combine packets; which one happens depends on the kernel implementation, and you are not guaranteed to have anything sane happen. The best case for you would be if the system returns a single packet per system call, in which case you read() into a maximally sized buffer and the returned length is that of the actual packet. However, many systems choose to retain the stream nature of read() and will return any information that comes in, losing the packet boundaries. In the case of DNS, you can almost get away with this anyway because the protocol specifies a maximum UDP request/response length of 255 octets sent as a single packet. If this is insufficient, you need to switch to TCP. In the case of a response, you will get a truncated response and will need to recognize it by parsing the data and retry the query over TCP. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

Hello,
If my understating is correct, I cannot use recvFrom since it calls recvfrom() with FFI. So, I use socketToHandle to translate a socket to a handle.
Sorry. This is my misunderstanding. recvFrom does not stop other threads at least on UNIX. So, my problem is solved. --Kazu
participants (2)
-
Brandon S. Allbery KF8NH
-
Kazu Yamamoto