[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