[Insight-developers] DICOM UID generation
Mathieu Malaterre
mathieu.malaterre at kitware.com
Thu Jan 6 11:29:27 EST 2005
Thanks a lot. I'll try to come with an implementation ASAP.
Getting the MAC address seems a lot better than IP. I'll also try to
look into the problem of time precision but this doesn't seems too hard.
Thanks for feedback.
Mathieu
David Clunie wrote:
> Hi Mathieu
>
> The use of IP address is very problematic.
>
> Most of us work using private IP addresses behind routers that do
> network address translation, therefore the chances of collisions
> based on IP address are extremely high. E.g. there are thousands
> of 10.1.1.1 and 192.168.1.1 hosts in the world.
>
> MAC address is much better, but harder to get in a platform
> neutral way. Some platforms have a hostid.
>
> For a timestamp, one needs precision well down into the millisecond
> range, and something like the Unix milliseconds since epoch might do.
>
> I would always try and include a thread and/or process number as
> well, since it is quite likely that separate threads or processes
> on the same machine might generate UIDs at the same time with a
> granularity of milliseconds, given the speed of today's servers.
>
> I try and throw in a random number if at all possible, just in case.
>
> Another possibility is to use some form of cryptographic random number
> generator that creates a number that is very, very likely to be unique.
>
> You might want to take a look at the Javadoc describing java.rmi.server.UID
> and java.security.SecureRandom for some ideas, even though you use a
> different platform.
>
> It also depends also on how deterministic one wants the generation process
> to be, if at all.
>
> More questions than answers perhaps, but the simplistic approach
> suggested below is very likely not robust enough for generating
> UIDs that will escape into a clinical PACS environment, where uniqueness
> is extremely important, because of a) the use of IP address and b) the
> use of perhaps insufficiently precise time. The inclusion of the "gdcm"
> as octal may not help since the root that precedes it should be
> unique enough to distinguish the toolkit, and all users of gdcm will be
> adding this extra unhelpful component.
>
> Discussing this makes me cringe when I think how inadequate some of
> the techniques I use in my own toolkits are under various circumstances.
> Time to revisit them again I suppose.
>
> David
>
> Mathieu Malaterre wrote:
>
>> David,
>>
>> Could you please comment on the code bellow. This is extracted
>> from GDCM CVS tree.
>>
>> The code works as follow:
>> echo "gdcm" | od -b
>> 0000000 147 144 143 155 012
>>
>> Then we build the UID with:
>>
>> radical (if passed in) + 147.144.143.155 + IP + time()
>>
>> Therefore even organization without radical can create unique
>> DICOM images internal within their organization.
>>
>> Mathieu
>>
>> /**
>> * \ingroup Util
>> * \brief Return the IP adress of the machine writting the DICOM image
>> */
>> std::string Util::GetIPAddress()
>> {
>> // This is a rip from
>> http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
>> #ifndef HOST_NAME_MAX
>> // SUSv2 guarantees that `Host names are limited to 255 bytes'.
>> // POSIX 1003.1-2001 guarantees that `Host names (not including the
>> // terminating NUL) are limited to HOST_NAME_MAX bytes'.
>> # define HOST_NAME_MAX 255
>> // In this case we should maybe check the string was not truncated.
>> // But I don't known how to check that...
>> #if defined(_MSC_VER) || defined(__BORLANDC__)
>> // with WinSock DLL we need to initialise the WinSock before using
>> gethostname
>> WORD wVersionRequested = MAKEWORD(1,0);
>> WSADATA WSAData;
>> int err = WSAStartup(wVersionRequested,&WSAData);
>> if (err != 0) {
>> /* Tell the user that we could not find a usable */
>> /* WinSock DLL. */
>> WSACleanup();
>> return "127.0.0.1";
>> }
>> #endif
>>
>> #endif //HOST_NAME_MAX
>>
>> std::string str;
>> char szHostName[HOST_NAME_MAX+1];
>> int r = gethostname(szHostName, HOST_NAME_MAX);
>>
>> if( r == 0 )
>> {
>> // Get host adresses
>> struct hostent * pHost = gethostbyname(szHostName);
>>
>> for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
>> {
>> for( int j = 0; j<pHost->h_length; j++ )
>> {
>> if( j > 0 ) str += ".";
>>
>> str += Util::Format("%u",
>> (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
>> }
>> // str now contains one local IP address
>>
>> #if defined(_MSC_VER) || defined(__BORLANDC__)
>> WSACleanup();
>> #endif
>>
>> }
>> }
>> // If an error occur r == -1
>> // Most of the time it will return 127.0.0.1...
>> return str;
>> }
>>
>> /**
>> * \ingroup Util
>> * \brief Creates a new UID. As stipulate in the DICOM ref
>> * each time a DICOM image is create it should have
>> * a unique identifier (URI)
>> */
>> std::string Util::CreateUniqueUID(const std::string& root)
>> {
>> // The code works as follow:
>> // echo "gdcm" | od -b
>> // 0000000 147 144 143 155 012
>> // Therefore we return
>> // radical + 147.144.143.155 + IP + time()
>> std::string radical = root;
>> if( !root.size() ) //anything better ?
>> {
>> radical = "0.0."; // Is this really usefull ?
>> }
>> // else
>> // A root was specified use it to forge our new UID:
>> radical += "147.144.143.155"; // gdcm
>> radical += ".";
>> radical += Util::GetIPAddress();
>> radical += ".";
>> radical += Util::GetCurrentDate();
>> radical += ".";
>> radical += Util::GetCurrentTime();
>>
>> return radical;
>> }
>
>
> _______________________________________________
> Insight-developers mailing list
> Insight-developers at itk.org
> http://www.itk.org/mailman/listinfo/insight-developers
>
More information about the Insight-developers
mailing list