libmongo-client 0.1.4
|
00001 /* mongo-utils.c - libmongo-client utility functions 00002 * Copyright 2011 Gergely Nagy <algernon@balabit.hu> 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00021 #include <glib.h> 00022 #include <glib/gprintf.h> 00023 00024 #include <sys/types.h> 00025 #include <string.h> 00026 #include <stdlib.h> 00027 #include <time.h> 00028 #include <unistd.h> 00029 #include <errno.h> 00030 00031 static guint32 machine_id = 0; 00032 static gint16 pid = 0; 00033 00034 void 00035 mongo_util_oid_init (gint32 mid) 00036 { 00037 pid_t p = getpid (); 00038 00039 if (mid == 0) 00040 { 00041 srand (time (NULL)); 00042 machine_id = rand (); 00043 } 00044 else 00045 machine_id = mid; 00046 00047 /* 00048 * If our pid has more than 16 bits, let half the bits modulate the 00049 * machine_id. 00050 */ 00051 if (sizeof (pid_t) > 2) 00052 { 00053 machine_id ^= pid >> 16; 00054 } 00055 pid = (gint16)p; 00056 } 00057 00058 guint8 * 00059 mongo_util_oid_new_with_time (gint32 ts, gint32 seq) 00060 { 00061 guint8 *oid; 00062 time_t t = GINT32_TO_BE (ts); 00063 gint32 tmp = GINT32_TO_BE (seq); 00064 00065 if (machine_id == 0 || pid == 0) 00066 return NULL; 00067 00068 oid = (guint8 *)g_new0 (guint8, 12); 00069 00070 /* Sequence number, last 3 bytes 00071 * For simplicity's sake, we put this in first, and overwrite the 00072 * first byte later. 00073 */ 00074 memcpy (oid + 4 + 2 + 2, &tmp, 4); 00075 /* First four bytes: the time, BE byte order */ 00076 memcpy (oid, &t, 4); 00077 /* Machine ID, byte order doesn't matter, 3 bytes */ 00078 memcpy (oid + 4, &machine_id, 3); 00079 /* PID, byte order doesn't matter, 2 bytes */ 00080 memcpy (oid + 4 + 3, &pid, 2); 00081 00082 return oid; 00083 } 00084 00085 guint8 * 00086 mongo_util_oid_new (gint32 seq) 00087 { 00088 return mongo_util_oid_new_with_time (time (NULL), seq); 00089 } 00090 00091 gchar * 00092 mongo_util_oid_as_string (const guint8 *oid) 00093 { 00094 gchar *str; 00095 gint j; 00096 00097 if (!oid) 00098 return NULL; 00099 00100 str = g_new (gchar, 26); 00101 for (j = 0; j < 12; j++) 00102 g_sprintf (&str[j * 2], "%02x", oid[j]); 00103 str[25] = 0; 00104 return str; 00105 } 00106 00107 gboolean 00108 mongo_util_parse_addr (const gchar *addr, gchar **host, gint *port) 00109 { 00110 gchar *port_s, *ep; 00111 glong p; 00112 00113 if (!addr || !host || !port) 00114 { 00115 if (host) 00116 *host = NULL; 00117 if (port) 00118 *port = -1; 00119 errno = EINVAL; 00120 return FALSE; 00121 } 00122 00123 /* Check for IPv6 literal */ 00124 if (addr[0] == '[') 00125 { 00126 /* Host is everything between [] */ 00127 port_s = strchr (addr + 1, ']'); 00128 if (!port_s || port_s - addr == 1) 00129 { 00130 *host = NULL; 00131 *port = -1; 00132 errno = EINVAL; 00133 return FALSE; 00134 } 00135 *host = g_strndup (addr + 1, port_s - addr - 1); 00136 00137 port_s += 2; 00138 if (port_s - addr >= (glong)strlen (addr)) 00139 return TRUE; 00140 } 00141 else 00142 { 00143 /* Dealing with something that's not an IPv6 literal */ 00144 00145 /* Split up to host:port */ 00146 port_s = g_strrstr (addr, ":"); 00147 if (!port_s) 00148 { 00149 *host = g_strdup (addr); 00150 return TRUE; 00151 } 00152 if (port_s == addr) 00153 { 00154 *host = NULL; 00155 *port = -1; 00156 errno = EINVAL; 00157 return FALSE; 00158 } 00159 port_s++; 00160 *host = g_strndup (addr, port_s - addr - 1); 00161 } 00162 00163 p = strtol (port_s, &ep, 10); 00164 if (p == LONG_MIN || p == LONG_MAX) 00165 { 00166 g_free (*host); 00167 *host = NULL; 00168 *port = -1; 00169 errno = ERANGE; 00170 return FALSE; 00171 } 00172 if (p < 0 || p > INT_MAX) 00173 { 00174 g_free (*host); 00175 *host = NULL; 00176 *port = -1; 00177 errno = ERANGE; 00178 return FALSE; 00179 } 00180 *port = (gint)p; 00181 00182 if (ep && *ep) 00183 { 00184 g_free (*host); 00185 *host = NULL; 00186 *port = -1; 00187 errno = EINVAL; 00188 return FALSE; 00189 } 00190 return TRUE; 00191 }