libmongo-client 0.1.4
src/mongo-client.c
Go to the documentation of this file.
00001 /* mongo-client.c - libmongo-client user API
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 "mongo-client.h"
00022 #include "bson.h"
00023 #include "mongo-wire.h"
00024 #include "libmongo-private.h"
00025 
00026 #include <glib.h>
00027 
00028 #include <string.h>
00029 #include <arpa/inet.h>
00030 #include <sys/types.h>
00031 #include <sys/socket.h>
00032 #include <netdb.h>
00033 #include <sys/uio.h>
00034 #include <netinet/in.h>
00035 #include <netinet/tcp.h>
00036 #include <fcntl.h>
00037 #include <unistd.h>
00038 #include <stdlib.h>
00039 #include <errno.h>
00040 
00041 #ifndef MSG_NOSIGNAL
00042 #define MSG_NOSIGNAL 0
00043 #endif
00044 
00045 static const int one = 1;
00046 
00047 mongo_connection *
00048 mongo_connect (const char *host, int port)
00049 {
00050   struct addrinfo *res = NULL, *r;
00051   struct addrinfo hints;
00052   int e, fd = -1;
00053   gchar *port_s;
00054   mongo_connection *conn;
00055 
00056   if (!host)
00057     {
00058       errno = EINVAL;
00059       return NULL;
00060     }
00061 
00062   conn = g_new0 (mongo_connection, 1);
00063 
00064   memset (&hints, 0, sizeof (hints));
00065   hints.ai_socktype = SOCK_STREAM;
00066 
00067 #ifdef __linux__
00068   hints.ai_flags = AI_ADDRCONFIG;
00069 #endif
00070 
00071   port_s = g_strdup_printf ("%d", port);
00072   e = getaddrinfo (host, port_s, &hints, &res);
00073   if (e != 0)
00074     {
00075       int err = errno;
00076 
00077       g_free (conn);
00078       g_free (port_s);
00079       errno = err;
00080       return NULL;
00081     }
00082   g_free (port_s);
00083 
00084   for (r = res; r != NULL; r = r->ai_next)
00085     {
00086       fd = socket (r->ai_family, r->ai_socktype, r->ai_protocol);
00087       if (fd != -1 && connect (fd, r->ai_addr, r->ai_addrlen) == 0)
00088         break;
00089       if (fd != -1)
00090         {
00091           close (fd);
00092           fd = -1;
00093         }
00094     }
00095   freeaddrinfo (res);
00096 
00097   if (fd == -1)
00098     {
00099       g_free (conn);
00100 
00101       errno = EADDRNOTAVAIL;
00102       return NULL;
00103     }
00104 
00105   setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (one));
00106 
00107   conn->fd = fd;
00108 
00109   return conn;
00110 }
00111 
00112 void
00113 mongo_disconnect (mongo_connection *conn)
00114 {
00115   if (!conn)
00116     {
00117       errno = ENOTCONN;
00118       return;
00119     }
00120 
00121   if (conn->fd >= 0)
00122     close (conn->fd);
00123 
00124   g_free (conn);
00125   errno = 0;
00126 }
00127 
00128 gboolean
00129 mongo_packet_send (mongo_connection *conn, const mongo_packet *p)
00130 {
00131   const guint8 *data;
00132   gint32 data_size;
00133   mongo_packet_header h;
00134   struct iovec iov[2];
00135   struct msghdr msg;
00136 
00137   if (!conn)
00138     {
00139       errno = ENOTCONN;
00140       return FALSE;
00141     }
00142   if (!p)
00143     {
00144       errno = EINVAL;
00145       return FALSE;
00146     }
00147 
00148   if (conn->fd < 0)
00149     {
00150       errno = EBADF;
00151       return FALSE;
00152     }
00153 
00154   if (!mongo_wire_packet_get_header_raw (p, &h))
00155     return FALSE;
00156 
00157   data_size = mongo_wire_packet_get_data (p, &data);
00158 
00159   if (data_size == -1)
00160     return FALSE;
00161 
00162   iov[0].iov_base = (void *)&h;
00163   iov[0].iov_len = sizeof (h);
00164   iov[1].iov_base = (void *)data;
00165   iov[1].iov_len = data_size;
00166 
00167   memset (&msg, 0, sizeof (struct msghdr));
00168   msg.msg_iov = iov;
00169   msg.msg_iovlen = 2;
00170 
00171   if (sendmsg (conn->fd, &msg, MSG_NOSIGNAL) != (gint32)sizeof (h) + data_size)
00172     return FALSE;
00173 
00174   conn->request_id = h.id;
00175 
00176   return TRUE;
00177 }
00178 
00179 mongo_packet *
00180 mongo_packet_recv (mongo_connection *conn)
00181 {
00182   mongo_packet *p;
00183   guint8 *data;
00184   guint32 size;
00185   mongo_packet_header h;
00186 
00187   if (!conn)
00188     {
00189       errno = ENOTCONN;
00190       return NULL;
00191     }
00192 
00193   if (conn->fd < 0)
00194     {
00195       errno = EBADF;
00196       return NULL;
00197     }
00198 
00199   memset (&h, 0, sizeof (h));
00200   if (recv (conn->fd, &h, sizeof (mongo_packet_header),
00201             MSG_NOSIGNAL | MSG_WAITALL) != sizeof (mongo_packet_header))
00202     {
00203       return NULL;
00204     }
00205 
00206   h.length = GINT32_FROM_LE (h.length);
00207   h.id = GINT32_FROM_LE (h.id);
00208   h.resp_to = GINT32_FROM_LE (h.resp_to);
00209   h.opcode = GINT32_FROM_LE (h.opcode);
00210 
00211   p = mongo_wire_packet_new ();
00212 
00213   if (!mongo_wire_packet_set_header_raw (p, &h))
00214     {
00215       int e = errno;
00216 
00217       mongo_wire_packet_free (p);
00218       errno = e;
00219       return NULL;
00220     }
00221 
00222   size = h.length - sizeof (mongo_packet_header);
00223   data = g_new0 (guint8, size);
00224   if ((guint32)recv (conn->fd, data, size, MSG_NOSIGNAL | MSG_WAITALL) != size)
00225     {
00226       int e = errno;
00227 
00228       g_free (data);
00229       mongo_wire_packet_free (p);
00230       errno = e;
00231       return NULL;
00232     }
00233 
00234   if (!mongo_wire_packet_set_data (p, data, size))
00235     {
00236       int e = errno;
00237 
00238       g_free (data);
00239       mongo_wire_packet_free (p);
00240       errno = e;
00241       return NULL;
00242     }
00243 
00244   g_free (data);
00245 
00246   return p;
00247 }
00248 
00249 gint32
00250 mongo_connection_get_requestid (const mongo_connection *conn)
00251 {
00252   if (!conn)
00253     {
00254       errno = ENOTCONN;
00255       return -1;
00256     }
00257 
00258   return conn->request_id;
00259 }
00260 
00261 gboolean
00262 mongo_connection_set_timeout (mongo_connection *conn, gint timeout)
00263 {
00264   struct timeval tv;
00265 
00266   if (!conn)
00267     {
00268       errno = ENOTCONN;
00269       return FALSE;
00270     }
00271   if (timeout < 0)
00272     {
00273       errno = ERANGE;
00274       return FALSE;
00275     }
00276 
00277   tv.tv_sec = timeout / 1000;
00278   tv.tv_usec = (timeout % 1000) * 1000;
00279 
00280   if (setsockopt (conn->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv)) == -1)
00281     return FALSE;
00282   if (setsockopt (conn->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (tv)) == -1)
00283     return FALSE;
00284   return TRUE;
00285 }
 All Data Structures Files Functions Variables Enumerations Enumerator Defines