XMMS2
src/lib/xmmsipc/msg.c
Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2011 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 #include <stdarg.h>
00018 #include <string.h>
00019 #include <stdlib.h>
00020 
00021 #include <errno.h>
00022 #include <time.h>
00023 #include <assert.h>
00024 
00025 #include "xmmspriv/xmms_list.h"
00026 #include "xmmsc/xmmsc_ipc_transport.h"
00027 #include "xmmsc/xmmsc_ipc_msg.h"
00028 #include "xmmsc/xmmsc_util.h"
00029 #include "xmmsc/xmmsc_sockets.h"
00030 #include "xmmsc/xmmsc_stdint.h"
00031 #include "xmmsc/xmmsv_coll.h"
00032 
00033 struct xmms_ipc_msg_St {
00034     xmmsv_t *bb;
00035     uint32_t xfered;
00036 };
00037 
00038 
00039 
00040 xmms_ipc_msg_t *
00041 xmms_ipc_msg_alloc (void)
00042 {
00043     xmms_ipc_msg_t *msg;
00044     static unsigned char empty[16] = {0,};
00045 
00046     msg = x_new0 (xmms_ipc_msg_t, 1);
00047     msg->bb = xmmsv_bitbuffer_new ();
00048     xmmsv_bitbuffer_put_data (msg->bb, empty, 16);
00049 
00050     return msg;
00051 }
00052 
00053 void
00054 xmms_ipc_msg_destroy (xmms_ipc_msg_t *msg)
00055 {
00056     x_return_if_fail (msg);
00057 
00058     xmmsv_unref (msg->bb);
00059     free (msg);
00060 }
00061 
00062 static void
00063 xmms_ipc_msg_update_length (xmmsv_t *bb)
00064 {
00065     int len;
00066 
00067     len = xmmsv_bitbuffer_len (bb);
00068 
00069     len /= 8;
00070     len -= XMMS_IPC_MSG_HEAD_LEN;
00071 
00072     xmmsv_bitbuffer_goto (bb, 12*8);
00073     xmmsv_bitbuffer_put_bits (bb, 32, len);
00074     xmmsv_bitbuffer_end (bb);
00075 }
00076 
00077 static uint32_t
00078 xmms_ipc_msg_get_length (const xmms_ipc_msg_t *msg)
00079 {
00080     int len, p;
00081     x_return_val_if_fail (msg, 0);
00082 
00083     p = xmmsv_bitbuffer_pos (msg->bb);
00084     xmmsv_bitbuffer_goto (msg->bb, 12*8);
00085     xmmsv_bitbuffer_get_bits (msg->bb, 32, &len);
00086     xmmsv_bitbuffer_goto (msg->bb, p);
00087     return len;
00088 }
00089 
00090 uint32_t
00091 xmms_ipc_msg_get_object (const xmms_ipc_msg_t *msg)
00092 {
00093     int obj, p;
00094     x_return_val_if_fail (msg, 0);
00095 
00096     p = xmmsv_bitbuffer_pos (msg->bb);
00097     xmmsv_bitbuffer_goto (msg->bb, 0);
00098     xmmsv_bitbuffer_get_bits (msg->bb, 32, &obj);
00099     xmmsv_bitbuffer_goto (msg->bb, p);
00100     return obj;
00101 }
00102 
00103 static void
00104 xmms_ipc_msg_set_object (xmms_ipc_msg_t *msg, uint32_t object)
00105 {
00106     x_return_if_fail (msg);
00107 
00108     xmmsv_bitbuffer_goto (msg->bb, 0);
00109     xmmsv_bitbuffer_put_bits (msg->bb, 32, object);
00110     xmmsv_bitbuffer_end (msg->bb);
00111 }
00112 
00113 uint32_t
00114 xmms_ipc_msg_get_cmd (const xmms_ipc_msg_t *msg)
00115 {
00116     int cmd, p;
00117     x_return_val_if_fail (msg, 0);
00118 
00119     p = xmmsv_bitbuffer_pos (msg->bb);
00120     xmmsv_bitbuffer_goto (msg->bb, 4 * 8);
00121     xmmsv_bitbuffer_get_bits (msg->bb, 32, &cmd);
00122     xmmsv_bitbuffer_goto (msg->bb, p);
00123     return cmd;
00124 }
00125 
00126 static void
00127 xmms_ipc_msg_set_cmd (xmms_ipc_msg_t *msg, uint32_t cmd)
00128 {
00129     x_return_if_fail (msg);
00130 
00131     xmmsv_bitbuffer_goto (msg->bb, 4 * 8);
00132     xmmsv_bitbuffer_put_bits (msg->bb, 32, cmd);
00133     xmmsv_bitbuffer_end (msg->bb);
00134 }
00135 
00136 void
00137 xmms_ipc_msg_set_cookie (xmms_ipc_msg_t *msg, uint32_t cookie)
00138 {
00139     xmmsv_bitbuffer_goto (msg->bb, 8 * 8);
00140     xmmsv_bitbuffer_put_bits (msg->bb, 32, cookie);
00141     xmmsv_bitbuffer_end (msg->bb);
00142 }
00143 
00144 uint32_t
00145 xmms_ipc_msg_get_cookie (const xmms_ipc_msg_t *msg)
00146 {
00147     int cookie, p;
00148     x_return_val_if_fail (msg, 0);
00149 
00150     p = xmmsv_bitbuffer_pos (msg->bb);
00151     xmmsv_bitbuffer_goto (msg->bb, 8 * 8);
00152     xmmsv_bitbuffer_get_bits (msg->bb, 32, &cookie);
00153     xmmsv_bitbuffer_goto (msg->bb, p);
00154     return cookie;
00155 }
00156 
00157 xmms_ipc_msg_t *
00158 xmms_ipc_msg_new (uint32_t object, uint32_t cmd)
00159 {
00160     xmms_ipc_msg_t *msg;
00161 
00162     msg = xmms_ipc_msg_alloc ();
00163 
00164     xmms_ipc_msg_set_cmd (msg, cmd);
00165     xmms_ipc_msg_set_object (msg, object);
00166 
00167     return msg;
00168 }
00169 
00170 
00171 /**
00172  * Try to write message to transport. If full message isn't written
00173  * the message will keep track of the amount of data written and not
00174  * write already written data next time.
00175  *
00176  * @returns TRUE if full message was written, FALSE otherwise.
00177  *               disconnected is set if transport was disconnected
00178  */
00179 bool
00180 xmms_ipc_msg_write_transport (xmms_ipc_msg_t *msg,
00181                               xmms_ipc_transport_t *transport,
00182                               bool *disconnected)
00183 {
00184     char *buf;
00185     unsigned int ret, len;
00186 
00187     x_return_val_if_fail (msg, false);
00188     x_return_val_if_fail (transport, false);
00189 
00190     xmmsv_bitbuffer_align (msg->bb);
00191 
00192     len = xmmsv_bitbuffer_len (msg->bb) / 8;
00193 
00194     x_return_val_if_fail (len > msg->xfered, true);
00195 
00196     buf = (char *) (xmmsv_bitbuffer_buffer (msg->bb) + msg->xfered);
00197     ret = xmms_ipc_transport_write (transport, buf, len - msg->xfered);
00198 
00199     if (ret == SOCKET_ERROR) {
00200         if (xmms_socket_error_recoverable ()) {
00201             return false;
00202         }
00203 
00204         if (disconnected) {
00205             *disconnected = true;
00206         }
00207 
00208         return false;
00209     } else if (!ret) {
00210         if (disconnected) {
00211             *disconnected = true;
00212         }
00213     } else {
00214         msg->xfered += ret;
00215     }
00216 
00217     return (len == msg->xfered);
00218 }
00219 
00220 /**
00221  * Try to read message from transport into msg.
00222  *
00223  * @returns TRUE if message is fully read.
00224  */
00225 bool
00226 xmms_ipc_msg_read_transport (xmms_ipc_msg_t *msg,
00227                              xmms_ipc_transport_t *transport,
00228                              bool *disconnected)
00229 {
00230     char buf[512];
00231     unsigned int ret, len, rlen;
00232 
00233     x_return_val_if_fail (msg, false);
00234     x_return_val_if_fail (transport, false);
00235 
00236     while (true) {
00237         len = XMMS_IPC_MSG_HEAD_LEN;
00238 
00239         if (msg->xfered >= XMMS_IPC_MSG_HEAD_LEN) {
00240             len += xmms_ipc_msg_get_length (msg);
00241 
00242             if (msg->xfered == len) {
00243                 return true;
00244             }
00245         }
00246 
00247         x_return_val_if_fail (msg->xfered < len, false);
00248 
00249         rlen = len - msg->xfered;
00250         if (rlen > sizeof (buf))
00251             rlen = sizeof (buf);
00252 
00253         ret = xmms_ipc_transport_read (transport, buf, rlen);
00254 
00255         if (ret == SOCKET_ERROR) {
00256             if (xmms_socket_error_recoverable ()) {
00257                 return false;
00258             }
00259 
00260             if (disconnected) {
00261                 *disconnected = true;
00262             }
00263 
00264             return false;
00265         } else if (ret == 0) {
00266             if (disconnected) {
00267                 *disconnected = true;
00268             }
00269 
00270             return false;
00271         } else {
00272             xmmsv_bitbuffer_goto (msg->bb, msg->xfered * 8);
00273             xmmsv_bitbuffer_put_data (msg->bb, (unsigned char *) buf, ret);
00274             msg->xfered += ret;
00275             xmmsv_bitbuffer_goto (msg->bb, XMMS_IPC_MSG_HEAD_LEN * 8);
00276         }
00277     }
00278 }
00279 
00280 uint32_t
00281 xmms_ipc_msg_put_value (xmms_ipc_msg_t *msg, xmmsv_t *v)
00282 {
00283     if (!xmmsv_bitbuffer_serialize_value (msg->bb, v))
00284         return false;
00285     xmms_ipc_msg_update_length (msg->bb);
00286     return xmmsv_bitbuffer_pos (msg->bb);
00287 }
00288 
00289 
00290 bool
00291 xmms_ipc_msg_get_value (xmms_ipc_msg_t *msg, xmmsv_t **val)
00292 {
00293     return xmmsv_bitbuffer_deserialize_value (msg->bb, val);
00294 }