]> git.stg.codes - stg.git/commitdiff
Merge branch 'stg-2.409' into stg-2.409-radius
authorMaxim Mamontov <faust.madf@gmail.com>
Sat, 20 Jun 2015 09:32:23 +0000 (12:32 +0300)
committerMaxim Mamontov <faust.madf@gmail.com>
Sat, 20 Jun 2015 09:32:23 +0000 (12:32 +0300)
37 files changed:
projects/rlm_stg/Makefile
projects/rlm_stg/build
projects/rlm_stg/event.h [deleted file]
projects/rlm_stg/iface.cpp
projects/rlm_stg/iface.h
projects/rlm_stg/rlm_stg.c
projects/rlm_stg/stg_client.cpp
projects/rlm_stg/stg_client.h
projects/rlm_stg/stgpair.h
projects/stargazer/plugins/other/radius/Makefile
projects/stargazer/plugins/other/radius/config.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/radius/config.h [new file with mode: 0644]
projects/stargazer/plugins/other/radius/conn.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/radius/conn.h [new file with mode: 0644]
projects/stargazer/plugins/other/radius/radius.cpp
projects/stargazer/plugins/other/radius/radius.h
projects/stargazer/plugins/other/radius/reader.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/radius/reader.h [new file with mode: 0644]
stglibs/common.lib/Makefile
stglibs/common.lib/blockio.cpp [new file with mode: 0644]
stglibs/common.lib/include/stg/blockio.h [new file with mode: 0644]
stglibs/sgcp.lib/Makefile [new file with mode: 0644]
stglibs/sgcp.lib/crypto.cpp [new file with mode: 0644]
stglibs/sgcp.lib/crypto.h [new file with mode: 0644]
stglibs/sgcp.lib/include/stg/sgcp_proto.h [new file with mode: 0644]
stglibs/sgcp.lib/include/stg/sgcp_transport.h [new file with mode: 0644]
stglibs/sgcp.lib/include/stg/sgcp_types.h [new file with mode: 0644]
stglibs/sgcp.lib/include/stg/sgcp_utils.h [new file with mode: 0644]
stglibs/sgcp.lib/proto.cpp [new file with mode: 0644]
stglibs/sgcp.lib/tcp.cpp [new file with mode: 0644]
stglibs/sgcp.lib/tcp.h [new file with mode: 0644]
stglibs/sgcp.lib/transport.cpp [new file with mode: 0644]
stglibs/sgcp.lib/udp.cpp [new file with mode: 0644]
stglibs/sgcp.lib/udp.h [new file with mode: 0644]
stglibs/sgcp.lib/unix.cpp [new file with mode: 0644]
stglibs/sgcp.lib/unix.h [new file with mode: 0644]
stglibs/sgcp.lib/utils.cpp [new file with mode: 0644]

index 05c43d95135b559866886ac904108ce3fc074cfc..548232a8a9b7a88f3748667d3c3c66580aea6d50 100644 (file)
@@ -13,7 +13,8 @@ SRCS = ./rlm_stg.c \
        ./stg_client.cpp
 
 STGLIBS = crypto \
-          common
+          common \
+          sgcp
 
 STGLIBS_INCS = $(addprefix -I ../../stglibs/,$(addsuffix .lib/include,$(STGLIBS)))
 STGLIBS_LIBS = $(addprefix -L ../../stglibs/,$(addsuffix .lib,$(STGLIBS)))
@@ -31,6 +32,7 @@ SEARCH_DIRS = -I ../../include
 
 OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
 
+CFLAGS += -fPIC $(DEFS) $(STGLIBS_INCS) $(SEARCH_DIRS)
 CXXFLAGS += -fPIC $(DEFS) $(STGLIBS_INCS) $(SEARCH_DIRS)
 CFLAGS += $(DEFS) $(STGLIBS_INCS) $(SEARCH_DIRS)
 LDFLAGS += -shared -Wl,-rpath,$(PREFIX)/usr/lib/stg -Wl,-E $(STGLIBS_LIBS)
index 179d526188d9aef6e1370ca024d04d01063a27e9..4894491a84c1800e1e44074a65bec4abbca1fd3a 100755 (executable)
@@ -61,7 +61,7 @@ printf "########################################################################
 printf "       Building rlm_stg for $sys $release\n"
 printf "#############################################################################\n"
 
-STG_LIBS="crypto.lib common.lib"
+STG_LIBS="crypto.lib common.lib sgcp.lib"
 
 if [ "$OS" = "linux" ]
 then
diff --git a/projects/rlm_stg/event.h b/projects/rlm_stg/event.h
deleted file mode 100644 (file)
index 83a72d0..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef FR_EVENT_H
-#define FR_EVENT_H
-
-/*
- * event.h     Simple event queue
- *
- * Version:    $Id: event.h,v 1.1 2010/08/14 04:13:52 faust Exp $
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * Copyright 2007 The FreeRADIUS server project
- * Copyright 2007 Alan DeKok <aland@deployingradius.com>
- */
-
-//#include <freeradius/ident.h>
-//RCSIDH(event_h, "$Id: event.h,v 1.1 2010/08/14 04:13:52 faust Exp $")
-
-typedef struct fr_event_list_t fr_event_list_t;
-typedef struct fr_event_t fr_event_t;
-
-typedef        void (*fr_event_callback_t)(void *);
-typedef        void (*fr_event_status_t)(struct timeval *);
-typedef void (*fr_event_fd_handler_t)(fr_event_list_t *el, int sock, void *ctx);
-
-fr_event_list_t *fr_event_list_create(fr_event_status_t status);
-void fr_event_list_free(fr_event_list_t *el);
-
-int fr_event_list_num_elements(fr_event_list_t *el);
-
-int fr_event_insert(fr_event_list_t *el,
-                     fr_event_callback_t callback,
-                     void *ctx, struct timeval *when, fr_event_t **ev_p);
-int fr_event_delete(fr_event_list_t *el, fr_event_t **ev_p);
-
-int fr_event_run(fr_event_list_t *el, struct timeval *when);
-
-int fr_event_now(fr_event_list_t *el, struct timeval *when);
-
-int fr_event_fd_insert(fr_event_list_t *el, int type, int fd,
-                        fr_event_fd_handler_t handler, void *ctx);
-int fr_event_fd_delete(fr_event_list_t *el, int type, int fd);
-int fr_event_loop(fr_event_list_t *el);
-void fr_event_loop_exit(fr_event_list_t *el, int code);
-
-#endif /* FR_HASH_H */
index a74f32594136bc65f37084535e91e5887b680721..485e9ef7439d9b3d1d5854e0a38429b8c6df472c 100644 (file)
 #include "iface.h"
 
-#include "thriftclient.h"
+#include "stg_client.h"
 
-int stgInstantiateImpl(const char * server, uint16_t port, const char * password)
+#include <cstring>
+
+#include <strings.h>
+
+namespace
 {
-    if (STG_CLIENT_ST::Get().Configure(server, port, password))
-        return 1;
 
-    return 0;
+STG_PAIR* toSTGPairs(const PAIRS& source)
+{
+    STG_PAIR * pairs = new STG_PAIR[source.size() + 1];
+    for (size_t pos = 0; pos < source.size(); ++pos) {
+        bzero(pairs[pos].key, sizeof(STG_PAIR::key));
+        bzero(pairs[pos].value, sizeof(STG_PAIR::value));
+        strncpy(pairs[pos].key, source[pos].first.c_str(), sizeof(STG_PAIR::key));
+        strncpy(pairs[pos].value, source[pos].second.c_str(), sizeof(STG_PAIR::value));
+        ++pos;
+    }
+    bzero(pairs[source.size()].key, sizeof(STG_PAIR::key));
+    bzero(pairs[source.size()].value, sizeof(STG_PAIR::value));
+
+    return pairs;
 }
 
-const STG_PAIR * stgAuthorizeImpl(const char * userName, const char * serviceType)
+PAIRS fromSTGPairs(const STG_PAIR* pairs)
 {
-    return STG_CLIENT_ST::Get().Authorize(userName, serviceType);
+    const STG_PAIR* pair = pairs;
+    PAIRS res;
+
+    while (!emptyPair(pair)) {
+        res.push_back(std::pair<std::string, std::string>(pair->key, pair->value));
+        ++pair;
+    }
+
+    return res;
 }
 
-const STG_PAIR * stgAuthenticateImpl(const char * userName, const char * serviceType)
+STG_RESULT toResult(const RESULT& source)
 {
-    return STG_CLIENT_ST::Get().Authenticate(userName, serviceType);
+    STG_RESULT result;
+    result.modify = toSTGPairs(source.modify);
+    result.reply = toSTGPairs(source.reply);
+    return result;
 }
 
-const STG_PAIR * stgPostAuthImpl(const char * userName, const char * serviceType)
+STG_RESULT emptyResult()
 {
-    return STG_CLIENT_ST::Get().PostAuth(userName, serviceType);
+    STG_RESULT result = {NULL, NULL};
+    return result;
 }
 
-/*const STG_PAIR * stgPreAcctImpl(const char * userName, const char * serviceType)
+std::string toString(const char* value)
 {
-    return STG_CLIENT_ST::Get().PreAcct(userName, serviceType);
-}*/
+    if (value == NULL)
+        return "";
+    else
+        return value;
+}
+
+STG_RESULT stgRequest(STG_CLIENT::TYPE type, const char* userName, const char* password, const STG_PAIR* pairs)
+{
+    STG_CLIENT* client = STG_CLIENT::get();
+    if (client == NULL) {
+        // TODO: log "Not configured"
+        return emptyResult();
+    }
+    try {
+        return toResult(client->request(type, toString(userName), toString(password), fromSTGPairs(pairs)));
+    } catch (const STG_CLIENT::Error& ex) {
+        // TODO: log error
+        return emptyResult();
+    }
+}
+
+}
+
+int stgInstantiateImpl(const char* address)
+{
+    if (STG_CLIENT::configure(toString(address)))
+        return 1;
+
+    return 0;
+}
+
+STG_RESULT stgAuthorizeImpl(const char* userName, const char* password, const STG_PAIR* pairs)
+{
+    return stgRequest(STG_CLIENT::AUTHORIZE, userName, password, pairs);
+}
+
+STG_RESULT stgAuthenticateImpl(const char* userName, const char* password, const STG_PAIR* pairs)
+{
+    return stgRequest(STG_CLIENT::AUTHENTICATE, userName, password, pairs);
+}
+
+STG_RESULT stgPostAuthImpl(const char* userName, const char* password, const STG_PAIR* pairs)
+{
+    return stgRequest(STG_CLIENT::POST_AUTH, userName, password, pairs);
+}
 
-const STG_PAIR * stgAccountingImpl(const char * userName, const char * serviceType, const char * statusType, const char * sessionId)
+STG_RESULT stgPreAcctImpl(const char* userName, const char* password, const STG_PAIR* pairs)
 {
-    return STG_CLIENT_ST::Get().Account(userName, serviceType, statusType, sessionId);
+    return stgRequest(STG_CLIENT::PRE_ACCT, userName, password, pairs);
 }
 
-void deletePairs(const STG_PAIR * pairs)
+STG_RESULT stgAccountingImpl(const char* userName, const char* password, const STG_PAIR* pairs)
 {
-    delete[] pairs;
+    return stgRequest(STG_CLIENT::ACCOUNT, userName, password, pairs);
 }
index 831c31231bae8c30e09869902c7b2c97d628655d..e863e939ce650d525c85bddf527138bd36f1b32f 100644 (file)
@@ -9,14 +9,12 @@
 extern "C" {
 #endif
 
-int stgInstantiateImpl(const char * server, uint16_t port, const char * password);
-const STG_PAIR * stgAuthorizeImpl(const char * userName, const char * serviceType);
-const STG_PAIR * stgAuthenticateImpl(const char * userName, const char * serviceType);
-const STG_PAIR * stgPostAuthImpl(const char * userName, const char * serviceType);
-/*const STG_PAIR * stgPreAcctImpl(const char * userName, const char * serviceType);*/
-const STG_PAIR * stgAccountingImpl(const char * userName, const char * serviceType, const char * statusType, const char * sessionId);
-
-void deletePairs(const STG_PAIR * pairs);
+int stgInstantiateImpl(const char* address);
+STG_RESULT stgAuthorizeImpl(const char* userName, const char* password, const STG_PAIR* vps);
+STG_RESULT stgAuthenticateImpl(const char* userName, const char* password, const STG_PAIR* vps);
+STG_RESULT stgPostAuthImpl(const char* userName, const char* password, const STG_PAIR* vps);
+STG_RESULT stgPreAcctImpl(const char* userName, const char* password, const STG_PAIR* vps);
+STG_RESULT stgAccountingImpl(const char* userName, const char* password, const STG_PAIR* vps);
 
 #ifdef __cplusplus
 }
index e1caf57504faeac210119071efb5fa963dd4f300..0333fadc55304795cbf2b3475895d6e5979a88ae 100644 (file)
@@ -26,6 +26,9 @@
  *
  */
 
+#include "iface.h"
+#include "stgpair.h"
+
 #ifndef NDEBUG
 #define NDEBUG
 #include <freeradius/ident.h>
 #undef NDEBUG
 #endif
 
-#include "stgpair.h"
-#include "iface.h"
+#include <stddef.h> // size_t
 
 typedef struct rlm_stg_t {
-    char * server;
-    uint16_t port;
-    char * password;
+    char* address;
 } rlm_stg_t;
 
 static const CONF_PARSER module_config[] = {
-  { "server",  PW_TYPE_STRING_PTR, offsetof(rlm_stg_t,server), NULL,  "localhost"},
-  { "port",  PW_TYPE_INTEGER,     offsetof(rlm_stg_t,port), NULL,  "9091" },
-  { "password",  PW_TYPE_STRING_PTR, offsetof(rlm_stg_t,password), NULL,  "123456"},
+  { "address",  PW_TYPE_STRING_PTR, offsetof(rlm_stg_t, address), NULL,  "unix:/var/run/stg.sock"},
 
   { NULL, -1, 0, NULL, NULL }        /* end the list */
 };
 
-int emptyPair(const STG_PAIR * pair);
+static void deletePairs(STG_PAIR* pairs)
+{
+    free(pairs);
+}
+
+static size_t toVPS(const STG_PAIR* pairs, VALUE_PAIR* vps)
+{
+    const STG_PAIR* pair = pairs;
+    size_t count = 0;
+
+    while (!emptyPair(pair)) {
+        VALUE_PAIR* vp = pairmake(pair->key, pair->value, T_OP_SET);
+        pairadd(&vps, vp);
+        DEBUG("Adding pair '%s': '%s'", pair->key, pair->value);
+        ++pair;
+        ++count;
+    }
+
+    return count;
+}
+
+static size_t toReply(STG_RESULT result, REQUEST* request)
+{
+    size_t count = 0;
+
+    count += toVPS(result.modify, request->config_items);
+    count += toVPS(result.reply, request->reply->vps);
+
+    deletePairs(result.modify);
+    deletePairs(result.reply);
+
+    return count;
+}
+
+static int countVPS(const VALUE_PAIR* pairs)
+{
+    unsigned count = 0;
+    while (pairs != NULL) {
+        ++count;
+        pairs = pairs->next;
+    }
+    return count;
+}
+
+static STG_PAIR* fromVPS(const VALUE_PAIR* pairs)
+{
+    unsigned size = countVPS(pairs);
+    STG_PAIR* res = (STG_PAIR*)malloc(sizeof(STG_PAIR) * (size + 1));
+    size_t pos = 0;
+    while (pairs != NULL) {
+        bzero(res[pos].key, sizeof(res[0].key));
+        bzero(res[pos].value, sizeof(res[0].value));
+        strncpy(res[pos].key, pairs->name, sizeof(res[0].key));
+        strncpy(res[pos].value, pairs->data.strvalue, sizeof(res[0].value));
+        ++pos;
+        pairs = pairs->next;
+    }
+    bzero(res[pos].key, sizeof(res[0].key));
+    bzero(res[pos].value, sizeof(res[0].value));
+    return res;
+}
 
 /*
  *    Do any per-module initialization that is separate to each
@@ -63,17 +121,17 @@ int emptyPair(const STG_PAIR * pair);
  *    that must be referenced in later calls, store a handle to it
  *    in *instance otherwise put a null pointer there.
  */
-static int stg_instantiate(CONF_SECTION *conf, void **instance)
+static int stg_instantiate(CONF_SECTION* conf, void** instance)
 {
-    rlm_stg_t *data;
+    rlm_stg_tdata;
 
     /*
      *    Set up a storage area for instance data
      */
     data = rad_malloc(sizeof(*data));
-    if (!data) {
+    if (!data)
         return -1;
-    }
+
     memset(data, 0, sizeof(*data));
 
     /*
@@ -85,7 +143,7 @@ static int stg_instantiate(CONF_SECTION *conf, void **instance)
         return -1;
     }
 
-    if (!stgInstantiateImpl(data->server, data->port)) {
+    if (!stgInstantiateImpl(data->address)) {
         free(data);
         return -1;
     }
@@ -101,45 +159,37 @@ static int stg_instantiate(CONF_SECTION *conf, void **instance)
  *    from the database. The authentication code only needs to check
  *    the password, the rest is done here.
  */
-static int stg_authorize(void *, REQUEST *request)
+static int stg_authorize(void* instance, REQUEST* request)
 {
-    const STG_PAIR * pairs;
-    const STG_PAIR * pair;
+    STG_RESULT result;
+    STG_PAIR* pairs = fromVPS(request->packet->vps);
     size_t count = 0;
+    const char* username = NULL;
+    const char* password = NULL;
 
     instance = instance;
 
     DEBUG("rlm_stg: stg_authorize()");
 
     if (request->username) {
-        DEBUG("rlm_stg: stg_authorize() request username field: '%s'", request->username->vp_strvalue);
+        username = request->username->data.strvalue;
+        DEBUG("rlm_stg: stg_authorize() request username field: '%s'", username);
     }
+
     if (request->password) {
-        DEBUG("rlm_stg: stg_authorize() request password field: '%s'", request->password->vp_strvalue);
+        password = request->password->data.strvalue;
+        DEBUG("rlm_stg: stg_authorize() request password field: '%s'", password);
     }
-    // Here we need to define Framed-Protocol
-    VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE);
-    if (svc) {
-        DEBUG("rlm_stg: stg_authorize() Service-Type defined as '%s'", svc->vp_strvalue);
-        pairs = stgAuthorizeImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue);
-    } else {
-        DEBUG("rlm_stg: stg_authorize() Service-Type undefined");
-        pairs = stgAuthorizeImpl((const char *)request->username->vp_strvalue, "");
-    }
-    if (!pairs) {
+
+    result = stgAuthorizeImpl(username, password, pairs);
+    deletePairs(pairs);
+
+    if (!result.modify && !result.reply) {
         DEBUG("rlm_stg: stg_authorize() failed.");
         return RLM_MODULE_REJECT;
     }
 
-    pair = pairs;
-    while (!emptyPair(pair)) {
-        VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET);
-        pairadd(&request->config_items, pwd);
-        DEBUG("Adding pair '%s': '%s'", pair->key, pair->value);
-        ++pair;
-        ++count;
-    }
-    deletePairs(pairs);
+    count = toReply(result, request);
 
     if (count)
         return RLM_MODULE_UPDATED;
@@ -150,37 +200,37 @@ static int stg_authorize(void *, REQUEST *request)
 /*
  *    Authenticate the user with the given password.
  */
-static int stg_authenticate(void *, REQUEST *request)
+static int stg_authenticate(void* instance, REQUEST* request)
 {
-    const STG_PAIR * pairs;
-    const STG_PAIR * pair;
+    STG_RESULT result;
+    STG_PAIR* pairs = fromVPS(request->packet->vps);
     size_t count = 0;
+    const char* username = NULL;
+    const char* password = NULL;
 
     instance = instance;
 
     DEBUG("rlm_stg: stg_authenticate()");
 
-    VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE);
-    if (svc) {
-        DEBUG("rlm_stg: stg_authenticate() Service-Type defined as '%s'", svc->vp_strvalue);
-        pairs = stgAuthenticateImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue);
-    } else {
-        DEBUG("rlm_stg: stg_authenticate() Service-Type undefined");
-        pairs = stgAuthenticateImpl((const char *)request->username->vp_strvalue, "");
+    if (request->username) {
+        username = request->username->data.strvalue;
+        DEBUG("rlm_stg: stg_authenticate() request username field: '%s'", username);
+    }
+
+    if (request->password) {
+        password = request->password->data.strvalue;
+        DEBUG("rlm_stg: stg_authenticate() request password field: '%s'", password);
     }
-    if (!pairs) {
+
+    result = stgAuthenticateImpl(username, password, pairs);
+    deletePairs(pairs);
+
+    if (!result.modify && !result.reply) {
         DEBUG("rlm_stg: stg_authenticate() failed.");
         return RLM_MODULE_REJECT;
     }
 
-    pair = pairs;
-    while (!emptyPair(pair)) {
-        VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET);
-        pairadd(&request->reply->vps, pwd);
-        ++pair;
-        ++count;
-    }
-    deletePairs(pairs);
+    count = toReply(result, request);
 
     if (count)
         return RLM_MODULE_UPDATED;
@@ -191,63 +241,78 @@ static int stg_authenticate(void *, REQUEST *request)
 /*
  *    Massage the request before recording it or proxying it
  */
-static int stg_preacct(void *, REQUEST *)
+static int stg_preacct(void* instance, REQUEST* request)
 {
+    STG_RESULT result;
+    STG_PAIR* pairs = fromVPS(request->packet->vps);
+    size_t count = 0;
+    const char* username = NULL;
+    const char* password = NULL;
+
     DEBUG("rlm_stg: stg_preacct()");
 
     instance = instance;
 
-    return RLM_MODULE_OK;
+    if (request->username) {
+        username = request->username->data.strvalue;
+        DEBUG("rlm_stg: stg_preacct() request username field: '%s'", username);
+    }
+
+    if (request->password) {
+        password = request->password->data.strvalue;
+        DEBUG("rlm_stg: stg_preacct() request password field: '%s'", password);
+    }
+
+    result = stgPreAcctImpl(username, password, pairs);
+    deletePairs(pairs);
+
+    if (!result.modify && !result.reply) {
+        DEBUG("rlm_stg: stg_preacct() failed.");
+        return RLM_MODULE_REJECT;
+    }
+
+    count = toReply(result, request);
+
+    if (count)
+        return RLM_MODULE_UPDATED;
+
+    return RLM_MODULE_NOOP;
 }
 
 /*
  *    Write accounting information to this modules database.
  */
-static int stg_accounting(void *, REQUEST * request)
+static int stg_accounting(void* instance, REQUEST* request)
 {
-    const STG_PAIR * pairs;
-    const STG_PAIR * pair;
+    STG_RESULT result;
+    STG_PAIR* pairs = fromVPS(request->packet->vps);
     size_t count = 0;
-
-    instance = instance;
+    const char* username = NULL;
+    const char* password = NULL;
 
     DEBUG("rlm_stg: stg_accounting()");
 
-    VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE);
-    VALUE_PAIR * sessid = pairfind(request->packet->vps, PW_ACCT_SESSION_ID);
-    VALUE_PAIR * sttype = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE);
+    instance = instance;
 
-    if (!sessid) {
-        DEBUG("rlm_stg: stg_accounting() Acct-Session-ID undefined");
-        return RLM_MODULE_FAIL;
+    if (request->username) {
+        username = request->username->data.strvalue;
+        DEBUG("rlm_stg: stg_accounting() request username field: '%s'", username);
     }
 
-    if (sttype) {
-        DEBUG("Acct-Status-Type := %s", sttype->vp_strvalue);
-        if (svc) {
-            DEBUG("rlm_stg: stg_accounting() Service-Type defined as '%s'", svc->vp_strvalue);
-            pairs = stgAccountingImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue, (const char *)sttype->vp_strvalue, (const char *)sessid->vp_strvalue);
-        } else {
-            DEBUG("rlm_stg: stg_accounting() Service-Type undefined");
-            pairs = stgAccountingImpl((const char *)request->username->vp_strvalue, "", (const char *)sttype->vp_strvalue, (const char *)sessid->vp_strvalue);
-        }
-    } else {
-        DEBUG("rlm_stg: stg_accounting() Acct-Status-Type := NULL");
-        return RLM_MODULE_OK;
+    if (request->password) {
+        password = request->password->data.strvalue;
+        DEBUG("rlm_stg: stg_accounting() request password field: '%s'", password);
     }
-    if (!pairs) {
+
+    result = stgAccountingImpl(username, password, pairs);
+    deletePairs(pairs);
+
+    if (!result.modify && !result.reply) {
         DEBUG("rlm_stg: stg_accounting() failed.");
         return RLM_MODULE_REJECT;
     }
 
-    pair = pairs;
-    while (!emptyPair(pair)) {
-        VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET);
-        pairadd(&request->reply->vps, pwd);
-        ++pair;
-        ++count;
-    }
-    deletePairs(pairs);
+    count = toReply(result, request);
 
     if (count)
         return RLM_MODULE_UPDATED;
@@ -265,49 +330,48 @@ static int stg_accounting(void *, REQUEST * request)
  *    max. number of logins, do a second pass and validate all
  *    logins by querying the terminal server (using eg. SNMP).
  */
-static int stg_checksimul(void *, REQUEST *request)
+static int stg_checksimul(void* instance, REQUEST* request)
 {
     DEBUG("rlm_stg: stg_checksimul()");
 
     instance = instance;
 
-    request->simul_count=0;
+    request->simul_count = 0;
 
     return RLM_MODULE_OK;
 }
 
-static int stg_postauth(void *, REQUEST *request)
+static int stg_postauth(void* instance, REQUEST* request)
 {
-    const STG_PAIR * pairs;
-    const STG_PAIR * pair;
+    STG_RESULT result;
+    STG_PAIR* pairs = fromVPS(request->packet->vps);
     size_t count = 0;
-
-    instance = instance;
+    const char* username = NULL;
+    const char* password = NULL;
 
     DEBUG("rlm_stg: stg_postauth()");
 
-    VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE);
+    instance = instance;
 
-    if (svc) {
-        DEBUG("rlm_stg: stg_postauth() Service-Type defined as '%s'", svc->vp_strvalue);
-        pairs = stgPostAuthImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue);
-    } else {
-        DEBUG("rlm_stg: stg_postauth() Service-Type undefined");
-        pairs = stgPostAuthImpl((const char *)request->username->vp_strvalue, "");
+    if (request->username) {
+        username = request->username->data.strvalue;
+        DEBUG("rlm_stg: stg_postauth() request username field: '%s'", username);
     }
-    if (!pairs) {
+
+    if (request->password) {
+        password = request->password->data.strvalue;
+        DEBUG("rlm_stg: stg_postauth() request password field: '%s'", password);
+    }
+
+    result = stgPostAuthImpl(username, password, pairs);
+    deletePairs(pairs);
+
+    if (!result.modify && !result.reply) {
         DEBUG("rlm_stg: stg_postauth() failed.");
         return RLM_MODULE_REJECT;
     }
 
-    pair = pairs;
-    while (!emptyPair(pair)) {
-        VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET);
-        pairadd(&request->reply->vps, pwd);
-        ++pair;
-        ++count;
-    }
-    deletePairs(pairs);
+    count = toReply(result, request);
 
     if (count)
         return RLM_MODULE_UPDATED;
@@ -315,9 +379,9 @@ static int stg_postauth(void *, REQUEST *request)
     return RLM_MODULE_NOOP;
 }
 
-static int stg_detach(void *instance)
+static int stg_detach(voidinstance)
 {
-    free(((struct rlm_stg_t *)instance)->server);
+    free(((struct rlm_stg_t*)instance)->address);
     free(instance);
     return 0;
 }
@@ -334,17 +398,17 @@ static int stg_detach(void *instance)
 module_t rlm_stg = {
     RLM_MODULE_INIT,
     "stg",
-    RLM_TYPE_THREAD_SAFE,        /* type */
-    stg_instantiate,        /* instantiation */
-    stg_detach,            /* detach */
+    RLM_TYPE_THREAD_SAFE, /* type */
+    stg_instantiate,      /* instantiation */
+    stg_detach,           /* detach */
     {
-        stg_authenticate,    /* authentication */
+        stg_authenticate, /* authentication */
         stg_authorize,    /* authorization */
-        stg_preacct,    /* preaccounting */
-        stg_accounting,    /* accounting */
-        stg_checksimul,    /* checksimul */
-        NULL,            /* pre-proxy */
-        NULL,            /* post-proxy */
-        stg_postauth            /* post-auth */
+        stg_preacct,      /* preaccounting */
+        stg_accounting,   /* accounting */
+        stg_checksimul,   /* checksimul */
+        NULL,    /* pre-proxy */
+        NULL,   /* post-proxy */
+        stg_postauth      /* post-auth */
     },
 };
index 113e71c97891ca42c284d73b4616f019eb9564f8..199aca905df76b3c5ba703fa21b35d7f42b907e1 100644 (file)
  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
-/*
- *  Realization of data access via Stargazer for RADIUS
- *
- *  $Revision: 1.8 $
- *  $Date: 2010/04/16 12:30:02 $
- *
- */
-
-#include <netdb.h>
-#include <sys/types.h>
-#include <unistd.h> // close
-
-#include <cerrno>
-#include <cstring>
-#include <vector>
-#include <utility>
-
-#include <stdexcept>
-
 #include "stg_client.h"
 
-typedef std::vector<std::pair<std::string, std::string> > PAIRS;
-
-//-----------------------------------------------------------------------------
+#include "stg/common.h"
 
-STG_CLIENT::STG_CLIENT(const std::string & host, uint16_t port, uint16_t lp, const std::string & pass)
-    : password(pass),
-      framedIP(0)
-{
-/*sock = socket(AF_INET, SOCK_DGRAM, 0);
-if (sock == -1)
-    {
-    std::string message = strerror(errno);
-    message = "Socket create error: '" + message + "'";
-    throw std::runtime_error(message);
-    }
-
-struct hostent * he = NULL;
-he = gethostbyname(host.c_str());
-if (he == NULL)
-    {
-    throw std::runtime_error("gethostbyname error");
-    }
+#include <stdexcept>
 
-outerAddr.sin_family = AF_INET;
-outerAddr.sin_port = htons(port);
-outerAddr.sin_addr.s_addr = *(uint32_t *)he->h_addr;
+namespace {
 
-InitEncrypt(&ctx, password);
+STG_CLIENT* stgClient = NULL;
 
-PrepareNet();*/
-}
-
-STG_CLIENT::~STG_CLIENT()
+unsigned fromType(STG_CLIENT::TYPE type)
 {
-/*close(sock);*/
+    return static_cast<unsigned>(type);
 }
 
-int STG_CLIENT::PrepareNet()
+STG::SGCP::TransportType toTransport(const std::string& value)
 {
-return 0;
+    std::string type = ToLower(value);
+    if (type == "unix") return STG::SGCP::UNIX;
+    else if (type == "udp") return STG::SGCP::UDP;
+    else if (type == "tcp") return STG::SGCP::TCP;
+    throw ChannelConfig::Error("Invalid transport type. Should be 'unix', 'udp' or 'tcp'.");
 }
 
-int STG_CLIENT::Send(const RAD_PACKET & packet)
-{
-/*char buf[RAD_MAX_PACKET_LEN];
-    
-Encrypt(&ctx, buf, (char *)&packet, sizeof(RAD_PACKET) / 8);
-
-int res = sendto(sock, buf, sizeof(RAD_PACKET), 0, (struct sockaddr *)&outerAddr, sizeof(outerAddr));
-
-if (res == -1)
-    errorStr = "Error sending data";
-
-return res;*/
 }
 
-int STG_CLIENT::RecvData(RAD_PACKET * packet)
+ChannelConfig::ChannelConfig(std::string addr)
+    : transport(STG::SGCP::TCP)
 {
-/*char buf[RAD_MAX_PACKET_LEN];
-int res;
-
-struct sockaddr_in addr;
-socklen_t len = sizeof(struct sockaddr_in);
-
-res = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, reinterpret_cast<struct sockaddr *>(&addr), &len);
-if (res == -1)
-    {
-    errorStr = "Error receiving data";
-    return -1;
+    // unix:pass@/var/run/stg.sock
+    // tcp:secret@192.168.0.1:12345
+    // udp:key@isp.com.ua:54321
+
+    size_t pos = addr.find_first_of(':');
+    if (pos == std::string::npos)
+        throw Error("Missing transport name.");
+    transport = toTransport(addr.substr(0, pos));
+    addr = addr.substr(pos + 1);
+    if (addr.empty())
+        throw Error("Missing address to connect to.");
+    pos = addr.find_first_of('@');
+    if (pos != std::string::npos) {
+        key = addr.substr(0, pos);
+        addr = addr.substr(pos + 1);
+        if (addr.empty())
+            throw Error("Missing address to connect to.");
     }
-
-Decrypt(&ctx, (char *)packet, buf, res / 8);
-
-return 0;*/
-}
-
-int STG_CLIENT::Request(RAD_PACKET * packet, const std::string & login, const std::string & svc, uint8_t packetType)
-{
-/*int res;
-
-memcpy((void *)&packet->magic, (void *)RAD_ID, RAD_MAGIC_LEN);
-packet->protoVer[0] = '0';
-packet->protoVer[1] = '1';
-packet->packetType = packetType;
-packet->ip = 0;
-strncpy((char *)packet->login, login.c_str(), RAD_LOGIN_LEN);
-strncpy((char *)packet->service, svc.c_str(), RAD_SERVICE_LEN);
-
-res = Send(*packet);
-if (res == -1)
-    return -1;
-
-res = RecvData(packet);
-if (res == -1)
-    return -1;
-
-if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
+    if (transport == STG::SGCP::UNIX)
     {
-    errorStr = "Magic invalid. Wanted: '";
-    errorStr += RAD_ID;
-    errorStr += "', got: '";
-    errorStr += (char *)packet->magic;
-    errorStr += "'";
-    return -1;
+        address = addr;
+        return;
     }
-
-return 0;*/
+    pos = addr.find_first_of(':');
+    if (pos == std::string::npos)
+        throw Error("Missing port.");
+    address = addr.substr(0, pos);
+    if (str2x(addr.substr(pos + 1), port))
+        throw Error("Invalid port value.");
 }
 
-//-----------------------------------------------------------------------------
-
-const STG_PAIRS * STG_CLIENT::Authorize(const std::string & login, const std::string & svc)
+STG_CLIENT::STG_CLIENT(const std::string& address)
+    : m_config(address),
+      m_proto(m_config.transport, m_config.key)
 {
-/*RAD_PACKET packet;
-
-userPassword = "";
-
-if (Request(&packet, login, svc, RAD_AUTZ_PACKET))
-    return -1;
-
-if (packet.packetType != RAD_ACCEPT_PACKET)
-    return -1;
-
-userPassword = (char *)packet.password;*/
-
-PAIRS pairs;
-pairs.push_back(std::make_pair("Cleartext-Password", userPassword));
-
-return ToSTGPairs(pairs);
+    try {
+        m_proto.connect(m_config.address, m_config.port);
+    } catch (const STG::SGCP::Proto::Error& ex) {
+        throw Error(ex.what());
+    }
 }
 
-const STG_PAIRS * STG_CLIENT::Authenticate(const std::string & login, const std::string & svc)
+STG_CLIENT::~STG_CLIENT()
 {
-/*RAD_PACKET packet;
-
-userPassword = "";
-
-if (Request(&packet, login, svc, RAD_AUTH_PACKET))
-    return -1;
-
-if (packet.packetType != RAD_ACCEPT_PACKET)
-    return -1;*/
-
-PAIRS pairs;
-
-return ToSTGPairs(pairs);
 }
 
-const STG_PAIRS * STG_CLIENT::PostAuth(const std::string & login, const std::string & svc)
+RESULT STG_CLIENT::request(TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs)
 {
-/*RAD_PACKET packet;
-
-userPassword = "";
-
-if (Request(&packet, login, svc, RAD_POST_AUTH_PACKET))
-    return -1;
-
-if (packet.packetType != RAD_ACCEPT_PACKET)
-    return -1;
-
-if (svc == "Framed-User")
-    framedIP = packet.ip;
-else
-    framedIP = 0;*/
-
-PAIRS pairs;
-pairs.push_back(std::make_pair("Framed-IP-Address", inet_ntostring(framedIP)));
-
-return ToSTGPairs(pairs);
+    m_writeHeader(type, userName, password);
+    m_writePairBlock(pairs);
+    RESULT result;
+    result.modify = m_readPairBlock();
+    result.reply = m_readPairBlock();
+    return result;
 }
 
-const STG_PAIRS * STG_CLIENT::PreAcct(const std::string & login, const std::String & service)
+STG_CLIENT* STG_CLIENT::get()
 {
-PAIRS pairs;
-
-return ToSTGPairs(pairs);
+    return stgClient;
 }
 
-const STG_PAIRS * STG_CLIENT::Account(const std::string & type, const std::string & login, const std::string & svc, const std::string & sessid)
+bool STG_CLIENT::configure(const std::string& address)
 {
-/*RAD_PACKET packet;
-
-userPassword = "";
-strncpy((char *)packet.sessid, sessid.c_str(), RAD_SESSID_LEN);
-
-if (type == "Start")
-    {
-    if (Request(&packet, login, svc, RAD_ACCT_START_PACKET))
-        return -1;
-    }
-else if (type == "Stop")
-    {
-    if (Request(&packet, login, svc, RAD_ACCT_STOP_PACKET))
-        return -1;
-    }
-else if (type == "Interim-Update")
-    {
-    if (Request(&packet, login, svc, RAD_ACCT_UPDATE_PACKET))
-        return -1;
-    }
-else
-    {
-    if (Request(&packet, login, svc, RAD_ACCT_OTHER_PACKET))
-        return -1;
+    if ( stgClient != NULL )
+        delete stgClient;
+    try {
+        stgClient = new STG_CLIENT(address);
+        return true;
+    } catch (const ChannelConfig::Error& ex) {
+        // TODO: Log it
     }
-
-if (packet.packetType != RAD_ACCEPT_PACKET)
-    return -1;*/
-
-PAIRS pairs;
-
-return ToSTGPairs(pairs);
+    return false;
 }
 
-//-----------------------------------------------------------------------------
-
-std::string STG_CLIENT_ST::m_host;
-uint16_t STG_CLIENT_ST::m_port(6666);
-std::string STG_CLIENT_ST::m_password;
-
-//-----------------------------------------------------------------------------
-
-STG_CLIENT * STG_CLIENT_ST::Get()
+void STG_CLIENT::m_writeHeader(TYPE type, const std::string& userName, const std::string& password)
 {
-    static STG_CLIENT * stgClient = NULL;
-    if ( stgClient == NULL )
-        stgClient = new STG_CLIENT(m_host, m_port, m_password);
-    return stgClient;
+    try {
+        m_proto.writeAll<uint64_t>(fromType(type));
+        m_proto.writeAll(userName);
+        m_proto.writeAll(password);
+    } catch (const STG::SGCP::Proto::Error& ex) {
+        throw Error(ex.what());
+    }
 }
 
-void STG_CLIENT_ST::Configure(const std::string & host, uint16_t port, const std::string & password)
+void STG_CLIENT::m_writePairBlock(const PAIRS& pairs)
 {
-    m_host = host;
-    m_port = port;
-    m_password = password;
+    try {
+        m_proto.writeAll<uint64_t>(pairs.size());
+        for (size_t i = 0; i < pairs.size(); ++i) {
+            m_proto.writeAll(pairs[i].first);
+            m_proto.writeAll(pairs[i].second);
+        }
+    } catch (const STG::SGCP::Proto::Error& ex) {
+        throw Error(ex.what());
+    }
 }
 
-//-----------------------------------------------------------------------------
-
-const STG_PAIR * ToSTGPairs(const PAIRS & source)
+PAIRS STG_CLIENT::m_readPairBlock()
 {
-    STG_PAIR * pairs = new STG_PAIR[source.size() + 1];
-    for (size_t pos = 0; pos < source.size(); ++pos) {
-        bzero(pairs[pos].key, sizeof(STG_PAIR::key));
-        bzero(pairs[pos].value, sizeof(STG_PAIR::value));
-        strncpy(pairs[pos].key, source[pos].first.c_str(), sizeof(STG_PAIR::key));
-        strncpy(pairs[pos].value, source[pos].second.c_str(), sizeof(STG_PAIR::value));
-        ++pos;
+    try {
+        size_t count = m_proto.readAll<uint64_t>();
+        if (count == 0)
+            return PAIRS();
+        PAIRS res(count);
+        for (size_t i = 0; i < count; ++i) {
+            res[i].first = m_proto.readAll<std::string>();
+            res[i].second = m_proto.readAll<std::string>();
+        }
+        return res;
+    } catch (const STG::SGCP::Proto::Error& ex) {
+        throw Error(ex.what());
     }
-    bzero(pairs[sources.size()].key, sizeof(STG_PAIR::key));
-    bzero(pairs[sources.size()].value, sizeof(STG_PAIR::value));
-
-    return pairs;
 }
index 5ee000c7e949b1e8735815c122db7d510036e10a..6315a0a5dc3d18ee2dda1a7256cf3b104c3ffe6d 100644 (file)
  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
-/*
- *  Header file for client part of data access via Stargazer for RADIUS
- *
- *  $Revision: 1.4 $
- *  $Date: 2010/04/16 12:30:02 $
- *
- */
-
 #ifndef STG_CLIENT_H
 #define STG_CLIENT_H
 
+#include "stg/sgcp_proto.h" // Proto
+#include "stg/sgcp_types.h" // TransportType
+#include "stg/os_int.h"
+
 #include <string>
+#include <vector>
+#include <utility>
+
+typedef std::vector<std::pair<std::string, std::string> > PAIRS;
 
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h> // socklen_t
+struct RESULT
+{
+    PAIRS modify;
+    PAIRS reply;
+};
 
-#include "stg/blowfish.h"
-#include "stg/rad_packets.h"
+struct ChannelConfig {
+    struct Error : std::runtime_error {
+        Error(const std::string& message) : runtime_error(message) {}
+    };
 
-#include "stgpair.h"
+    ChannelConfig(std::string address);
+
+    STG::SGCP::TransportType transport;
+    std::string key;
+    std::string address;
+    uint16_t port;
+};
 
 class STG_CLIENT
 {
 public:
-    STG_CLIENT(const std::string & host, uint16_t port, const std::string & password);
+    enum TYPE {
+        AUTHORIZE,
+        AUTHENTICATE,
+        POST_AUTH,
+        PRE_ACCT,
+        ACCOUNT
+    };
+    struct Error : std::runtime_error {
+        Error(const std::string& message) : runtime_error(message) {}
+    };
+
+    STG_CLIENT(const std::string& address);
     ~STG_CLIENT();
 
-    const STG_PAIR * Authorize(const std::string & login, const std::string & service);
-    const STG_PAIR * Authenticate(const std::string & login, const std::string & service);
-    const STG_PAIR * PostAuth(const std::string & login, const std::string & service);
-    const STG_PAIR * PreAcct(const std::string & login, const std::string & service);
-    const STG_PAIR * Account(const std::string & type, const std::string & login, const std::string & service, const std::string & sessionId);
-
-private:
-    std::string password;
-
-    int PrepareNet();
+    static STG_CLIENT* get();
+    static bool configure(const std::string& address);
 
-    int Request(RAD_PACKET * packet, const std::string & login, const std::string & svc, uint8_t packetType);
+    RESULT request(TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs);
 
-    int RecvData(RAD_PACKET * packet);
-    int Send(const RAD_PACKET & packet);
-};
+private:
+    ChannelConfig m_config;
+    STG::SGCP::Proto m_proto;
 
-struct STG_CLIENT_ST
-{
-    public:
-        static void Configure(const std::string & host, uint16_t port, const std::string & password);
-        static STG_CLIENT * Get();
-
-    private:
-        static std::string m_host;
-        static uint16_t m_port;
-        static std::string m_password;
+    void m_writeHeader(TYPE type, const std::string& userName, const std::string& password);
+    void m_writePairBlock(const PAIRS& source);
+    PAIRS m_readPairBlock();
 };
 
 #endif
index 19b42bc182fe724ea1d83db6faf9639372b2e18f..dba9e3eb4b5af5c1643337423f54c0392f8a3499 100644 (file)
@@ -1,12 +1,33 @@
 #ifndef __STG_STGPAIR_H__
 #define __STG_STGPAIR_H__
 
+#include <stddef.h>
+
 #define STGPAIR_KEYLENGTH 64
 #define STGPAIR_VALUELENGTH 256
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct STG_PAIR {
     char key[STGPAIR_KEYLENGTH];
     char value[STGPAIR_VALUELENGTH];
 } STG_PAIR;
 
+typedef struct STG_RESULT {
+    STG_PAIR* modify;
+    STG_PAIR* reply;
+} STG_RESULT;
+
+inline
+int emptyPair(const STG_PAIR* pair)
+{
+    return pair != NULL && pair->key[0] != '\0' && pair->value[0] != '\0';
+}
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 62a05183acbb016994b74df5a7e8a34b9c6dbc85..dd7366981481e63aacb82ead660ff7b35d54eaf0 100644 (file)
@@ -8,7 +8,8 @@ LIBS += $(LIB_THREAD)
 
 PROG = mod_radius.so
 
-SRCS = ./radius.cpp
+SRCS = radius.cpp \
+       config.cpp
 
 STGLIBS = common \
          crypto \
diff --git a/projects/stargazer/plugins/other/radius/config.cpp b/projects/stargazer/plugins/other/radius/config.cpp
new file mode 100644 (file)
index 0000000..8a90567
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "config.h"
+
+#include "stg/common.h"
+
+#include <vector>
+#include <stdexcept>
+
+#include <strings.h> // strncasecmp
+
+using STG::Config;
+
+namespace
+{
+
+struct ParserError : public std::runtime_error
+{
+    ParserError(size_t pos, const std::string& message)
+        : runtime_error("Parsing error at position " + x2str(pos) + ". " + message),
+          position(pos),
+          error(message)
+    {}
+
+    size_t position;
+    std::string error;
+};
+
+size_t skipSpaces(const std::string& value, size_t start)
+{
+    while (start < value.length() && std::isspace(value[start]))
+        ++start;
+    return start;
+}
+
+size_t checkChar(const std:string& value, size_t start, char ch)
+{
+    if (start >= value.length())
+        throw ParserError(start, "Unexpected end of string. Expected '" + std::string(ch) + "'.");
+    if (value[start] != ch)
+        throw ParserError(start, "Expected '" + std::string(ch) + "', got '" + std::string(value[start]) + "'.");
+    return start + 1;
+}
+
+std::pair<size_t, std::string> readString(const std::string& value, size_t start)
+{
+    std::string dest;
+    while (start < value.length() && !std::isspace(value[start]))
+        dest.push_back(value[start++]);
+    if (dest.empty()) {
+        if (start == value.length())
+            throw ParserError(start, "Unexpected end of string. Expected string.");
+        else
+            throw ParserError(start, "Unexpected whitespace. Expected string.");
+    }
+    return dest;
+}
+
+Config::Pairs toPairs(const std::vector<std::string>& values)
+{
+    if (values.empty())
+        return Config::Pairs();
+    std::string value(values[0]);
+    Config::Pairs res;
+    size_t start = 0;
+    while (start < value.size()) {
+        Config::Pair pair;
+        start = skipSpaces(value, start);
+        size_t pairStart = start;
+        start = checkChar(value, start, '(');
+        std::pair<size_t, std::string> key = readString(value, start);
+        start = key.first;
+        pair.first = key.second;
+        start = skipSpaces(value, start);
+        start = checkChar(value, start, ',')
+        start = skipSpaces(value, start);
+        std::pair<size_t, std::string> value = readString(value, start);
+        start = key.first;
+        pair.second = value.second;
+        start = skipSpaces(value, start);
+        start = checkChar(value, start, ')');
+        if (res.find(pair.first) != res.end())
+            throw ParserError(pairStart, "Duplicate field.");
+        res.insert(pair);
+    }
+    return res;
+}
+
+bool toBool(const std::vector<std::string>& values)
+{
+    if (values.empty())
+        return false;
+    std::string value(values[0]);
+    return strncasecmp(value.c_str(), "yes", 3) == 0;
+}
+
+std::string toString(const std::vector<std::string>& values)
+{
+    if (values.empty())
+        return "";
+    return values[0];
+}
+
+template <typename T>
+T toInt(const std::vector<std::string>& values)
+{
+    if (values.empty())
+        return 0;
+    T res = 0;
+    if (srt2x(values[0], res) == 0)
+        return res;
+    return 0;
+}
+
+Config::Pairs parseVector(const std::string& paramName, const MODULE_SETTINGS& params)
+{
+    for (size_t i = 0; i < params.moduleParams.size(); ++i)
+        if (params.moduleParams[i].first == paramName)
+            return toPairs(params.moduleParams[i].second);
+    return Config::Pairs();
+}
+
+bool parseBool(const std::string& paramName, const MODULE_SETTINGS& params)
+{
+    for (size_t i = 0; i < params.moduleParams.size(); ++i)
+        if (params.moduleParams[i].first == paramName)
+            return toBool(params.moduleParams[i].second);
+    return false;
+}
+
+std::string parseString(const std::string& paramName, const MODULE_SETTINGS& params)
+{
+    for (size_t i = 0; i < params.moduleParams.size(); ++i)
+        if (params.moduleParams[i].first == paramName)
+            return toString(params.moduleParams[i].second);
+    return "";
+}
+
+template <typename T>
+T parseInt(const std::string& paramName, const MODULE_SETTINGS& params)
+{
+    for (size_t i = 0; i < params.moduleParams.size(); ++i)
+        if (params.moduleParams[i].first == paramName)
+            return toInt<T>(params.moduleParams[i].second);
+    return 0;
+}
+
+} // namespace anonymous
+
+Config::Config(const MODULE_SETTINGS& settings)
+    : match(parseVector("match", settings)),
+      modify(parseVector("modify", settings)),
+      reply(parseVector("reply", settings)),
+      verbose(parseBool("verbose", settings)),
+      bindAddress(parseString("bind_address", settings)),
+      port(parseInt<uint16_t>("port", settings)),
+      key(parseString("key", settings))
+{
+}
diff --git a/projects/stargazer/plugins/other/radius/config.h b/projects/stargazer/plugins/other/radius/config.h
new file mode 100644 (file)
index 0000000..8e5055d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_RADIUS_CONFIG_H__
+#define __STG_RADIUS_CONFIG_H__
+
+#include "stg/module_settings.h"
+
+#include "stg/os_int.h"
+
+#include <map>
+#include <string>
+
+namespace STG
+{
+
+struct Config
+{
+    typedef std::map<std::string, std::string> Pairs;
+    typedef Pairs::value_type Pair;
+
+    Config(const MODULE_SETTINGS& settings);
+
+    Pairs match;
+    Pairs modify;
+    Pairs reply;
+
+    bool verbose;
+
+    std::string bindAddress;
+    uint16_t port;
+    std::string key;
+};
+
+} // namespace STG
+
+#endif
diff --git a/projects/stargazer/plugins/other/radius/conn.cpp b/projects/stargazer/plugins/other/radius/conn.cpp
new file mode 100644 (file)
index 0000000..223eb2c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "conn.h"
+
+#include "config.h"
+
+#include "stg/users.h"
+#include "stg/user.h"
+#include "stg/logger.h"
+#include "stg/common.h"
+
+#include <cstring>
+#include <cerrno>
+
+using STG::Conn;
+
+Conn::Conn(USERS& users, PLUGIN_LOGGER & logger, const Config& config)
+    : m_users(users),
+      m_logger(logger),
+      m_config(config)
+{
+}
+
+Conn::~Conn()
+{
+}
+
+bool Conn::read()
+{
+    ssize_t res = read(m_sock, m_buffer, m_bufferSize);
+    if (res < 0)
+    {
+        m_state = ERROR;
+        Log(__FILE__, "Failed to read data from " + inet_ntostring(IP()) + ":" + x2str(port()) + ". Reason: '" + strerror(errno) + "'");
+        return false;
+    }
+    if (res == 0 && m_state != DATA) // EOF is ok for data.
+    {
+        m_state = ERROR;
+        Log(__FILE__, "Failed to read data from " + inet_ntostring(IP()) + ":" + x2str(port()) + ". Unexpected EOF.");
+        return false;
+    }
+    m_bufferSize -= res;
+    return HandleBuffer(res);
+}
diff --git a/projects/stargazer/plugins/other/radius/conn.h b/projects/stargazer/plugins/other/radius/conn.h
new file mode 100644 (file)
index 0000000..31ebe1d
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONFIG_CONN_H__
+#define __STG_SGCONFIG_CONN_H__
+
+#include "stg/os_int.h"
+
+#include <stdexcept>
+#include <string>
+
+class USERS;
+
+namespace STG
+{
+
+class Conn
+{
+    public:
+        struct Error : public std::runtime_error
+        {
+            Error(const std::string& message) : runtime_error(message.c_str()) {}
+        };
+
+        Conn(USERS& users, PLUGIN_LOGGER& logger, const Config& config);
+        ~Conn();
+
+        int sock() const { return m_sock; }
+
+        bool read();
+
+    private:
+        USERS& m_users;
+        PLUGIN_LOGGER& m_logger;
+        const Config& m_config;
+};
+
+}
+
+#endif
index 8e52cdb48ba203f8763082f67ef58f711de00672..fe989b288d42bc3c954a075fa1183724805be367 100644 (file)
  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
-/*
- *  This file contains a realization of radius data access plugin for Stargazer
- *
- *  $Revision: 1.14 $
- *  $Date: 2009/12/13 14:17:13 $
- *
- */
-
-#include <csignal>
-#include <cerrno>
-#include <algorithm>
+#include "radius.h"
 
 #include "stg/store.h"
-#include "stg/common.h"
-#include "stg/user_conf.h"
-#include "stg/user_property.h"
+#include "stg/users.h"
 #include "stg/plugin_creator.h"
-#include "radius.h"
 
-extern volatile time_t stgTime;
+#include <csignal>
+#include <cerror>
+#include <cstring>
 
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
 namespace
 {
-PLUGIN_CREATOR<RADIUS> radc;
 
-void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password);
-void Decrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8);
-void Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8);
-}
-extern "C" PLUGIN * GetPlugin();
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-PLUGIN * GetPlugin()
-{
-return radc.GetPlugin();
+PLUGIN_CREATOR<RADIUS> creator;
+
 }
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-int RAD_SETTINGS::ParseServices(const std::vector<std::string> & str, std::list<std::string> * lst)
+
+extern "C" PLUGIN * GetPlugin()
 {
-std::copy(str.begin(), str.end(), std::back_inserter(*lst));
-std::list<std::string>::iterator it(std::find(lst->begin(),
-                               lst->end(),
-                               "empty"));
-if (it != lst->end())
-    *it = "";
-
-return 0;
+    return creator.GetPlugin();
 }
-//-----------------------------------------------------------------------------
-int RAD_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
-{
-int p;
-PARAM_VALUE pv;
-std::vector<PARAM_VALUE>::const_iterator pvi;
-///////////////////////////
-pv.param = "Port";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end())
-    {
-    errorStr = "Parameter \'Port\' not found.";
-    printfd(__FILE__, "Parameter 'Port' not found\n");
-    return -1;
-    }
-if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
-    {
-    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
-    printfd(__FILE__, "Cannot parse parameter 'Port'\n");
-    return -1;
-    }
-port = static_cast<uint16_t>(p);
-///////////////////////////
-pv.param = "Password";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end())
-    {
-    errorStr = "Parameter \'Password\' not found.";
-    printfd(__FILE__, "Parameter 'Password' not found\n");
-    return -1;
-    }
-password = pvi->value[0];
-///////////////////////////
-pv.param = "AuthServices";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi != s.moduleParams.end())
-    {
-    ParseServices(pvi->value, &authServices);
-    }
-///////////////////////////
-pv.param = "AcctServices";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi != s.moduleParams.end())
-    {
-    ParseServices(pvi->value, &acctServices);
-    }
 
-return 0;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
 RADIUS::RADIUS()
-    : ctx(),
-      errorStr(),
-      radSettings(),
-      settings(),
-      authServices(),
-      acctServices(),
-      sessions(),
-      nonstop(false),
-      isRunning(false),
-      users(NULL),
-      stgSettings(NULL),
-      store(NULL),
-      thread(),
-      mutex(),
-      sock(-1),
-      packet(),
-      logger(GetPluginLogger(GetStgLogger(), "radius"))
+    : m_running(false),
+      m_stopped(true),
+      m_users(NULL),
+      m_store(NULL),
+      m_logger(GetPluginLogger(GetStgLogger(), "radius"))
 {
-InitEncrypt(&ctx, "");
 }
-//-----------------------------------------------------------------------------
+
 int RADIUS::ParseSettings()
 {
-int ret = radSettings.ParseSettings(settings);
-if (ret)
-    errorStr = radSettings.GetStrError();
-return ret;
-}
-//-----------------------------------------------------------------------------
-int RADIUS::PrepareNet()
-{
-sock = socket(AF_INET, SOCK_DGRAM, 0);
-
-if (sock < 0)
-    {
-    errorStr = "Cannot create socket.";
-    logger("Cannot create a socket: %s", strerror(errno));
-    printfd(__FILE__, "Cannot create socket\n");
-    return -1;
-    }
-
-struct sockaddr_in inAddr;
-inAddr.sin_family = AF_INET;
-inAddr.sin_port = htons(radSettings.GetPort());
-inAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
-
-if (bind(sock, (struct sockaddr*)&inAddr, sizeof(inAddr)) < 0)
-    {
-    errorStr = "RADIUS: Bind failed.";
-    logger("Cannot bind the socket: %s", strerror(errno));
-    printfd(__FILE__, "Cannot bind socket\n");
-    return -1;
+    try {
+        m_config = STG::Config(m_settings);
+        return 0;
+    } catch (const std::runtime_error& ex) {
+        m_logger("Failed to parse settings. %s", ex.what());
+        return -1;
     }
-
-return 0;
 }
-//-----------------------------------------------------------------------------
-int RADIUS::FinalizeNet()
-{
-close(sock);
-return 0;
-}
-//-----------------------------------------------------------------------------
+
 int RADIUS::Start()
 {
-std::string password(radSettings.GetPassword());
-
-authServices = radSettings.GetAuthServices();
-acctServices = radSettings.GetAcctServices();
-
-InitEncrypt(&ctx, password);
+    if (m_running)
+        return 0;
 
-nonstop = true;
+    int res = pthread_create(&m_thread, NULL, run, this);
+    if (res == 0)
+        return 0;
 
-if (PrepareNet())
-    {
+    m_error = strerror(res);
+    m_logger("Failed to create thread: '" + m_error + "'.");
     return -1;
-    }
-
-if (!isRunning)
-    {
-    if (pthread_create(&thread, NULL, Run, this))
-        {
-        errorStr = "Cannot create thread.";
-       logger("Cannot create thread.");
-        printfd(__FILE__, "Cannot create thread\n");
-        return -1;
-        }
-    }
-
-errorStr = "";
-return 0;
 }
-//-----------------------------------------------------------------------------
+
 int RADIUS::Stop()
 {
-if (!IsRunning())
-    return 0;
-
-nonstop = false;
-
-std::map<std::string, RAD_SESSION>::iterator it;
-for (it = sessions.begin(); it != sessions.end(); ++it)
-    {
-    USER_PTR ui;
-    if (users->FindByName(it->second.userName, &ui))
-        {
-        users->Unauthorize(ui->GetLogin(), this);
-        }
-    }
-sessions.erase(sessions.begin(), sessions.end());
+    if (m_stopped)
+        return 0;
 
-FinalizeNet();
+    m_running = false;
 
-if (isRunning)
-    {
-    //5 seconds to thread stops itself
-    for (int i = 0; i < 25 && isRunning; i++)
-        {
+    for (size_t i = 0; i < 25 && !m_stopped; i++) {
         struct timespec ts = {0, 200000000};
         nanosleep(&ts, NULL);
-        }
     }
 
-if (isRunning)
-    return -1;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * RADIUS::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-RADIUS * rad = static_cast<RADIUS *>(d);
-RAD_PACKET packet;
-
-rad->isRunning = true;
-
-while (rad->nonstop)
-    {
-    if (!WaitPackets(rad->sock))
-        {
-        continue;
-        }
-    struct sockaddr_in outerAddr;
-    if (rad->RecvData(&packet, &outerAddr))
-        {
-        printfd(__FILE__, "RADIUS::Run Error on RecvData\n");
-        }
-    else
-        {
-        if (rad->ProcessData(&packet))
-            {
-            packet.packetType = RAD_REJECT_PACKET;
-            }
-        rad->Send(packet, &outerAddr);
-        }
+    if (m_stopped) {
+        pthread_join(m_thread, NULL);
+        return 0;
     }
 
-rad->isRunning = false;
-
-return NULL;
-}
-//-----------------------------------------------------------------------------
-int RADIUS::RecvData(RAD_PACKET * packet, struct sockaddr_in * outerAddr)
-{
-    int8_t buf[RAD_MAX_PACKET_LEN];
-    socklen_t outerAddrLen = sizeof(struct sockaddr_in);
-    ssize_t dataLen = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, reinterpret_cast<struct sockaddr *>(outerAddr), &outerAddrLen);
-    if (dataLen < 0)
-       {
-       logger("recvfrom error: %s", strerror(errno));
-       return -1;
-       }
-    if (dataLen == 0)
-       return -1;
-
-    Decrypt(&ctx, (char *)packet, (const char *)buf, dataLen / 8);
-
-    if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
-        {
-        printfd(__FILE__, "RADIUS::RecvData Error magic. Wanted: '%s', got: '%s'\n", RAD_ID, packet->magic);
-        return -1;
-        }
-
-    return 0;
-}
-//-----------------------------------------------------------------------------
-ssize_t RADIUS::Send(const RAD_PACKET & packet, struct sockaddr_in * outerAddr)
-{
-size_t len = sizeof(RAD_PACKET);
-char buf[1032];
-
-Encrypt(&ctx, buf, (char *)&packet, len / 8);
-ssize_t res = sendto(sock, buf, len, 0, reinterpret_cast<struct sockaddr *>(outerAddr), sizeof(struct sockaddr_in));
-if (res < 0)
-    logger("sendto error: %s", strerror(errno));
-return res;
-}
-//-----------------------------------------------------------------------------
-int RADIUS::ProcessData(RAD_PACKET * packet)
-{
-if (strncmp((const char *)packet->protoVer, "01", 2))
-    {
-    printfd(__FILE__, "RADIUS::ProcessData packet.protoVer incorrect\n");
+    m_error = "Failed to stop thread.";
+    m_logger(m_error);
     return -1;
-    }
-switch (packet->packetType)
-    {
-    case RAD_AUTZ_PACKET:
-        return ProcessAutzPacket(packet);
-    case RAD_AUTH_PACKET:
-        return ProcessAuthPacket(packet);
-    case RAD_POST_AUTH_PACKET:
-        return ProcessPostAuthPacket(packet);
-    case RAD_ACCT_START_PACKET:
-        return ProcessAcctStartPacket(packet);
-    case RAD_ACCT_STOP_PACKET:
-        return ProcessAcctStopPacket(packet);
-    case RAD_ACCT_UPDATE_PACKET:
-        return ProcessAcctUpdatePacket(packet);
-    case RAD_ACCT_OTHER_PACKET:
-        return ProcessAcctOtherPacket(packet);
-    default:
-        printfd(__FILE__, "RADIUS::ProcessData Unsupported packet type: %d\n", packet->packetType);
-        return -1;
-    };
 }
 //-----------------------------------------------------------------------------
-int RADIUS::ProcessAutzPacket(RAD_PACKET * packet)
+void* RADIUS::run(void* d)
 {
-USER_CONF conf;
-
-if (!IsAllowedService((char *)packet->service))
-    {
-    printfd(__FILE__, "RADIUS::ProcessAutzPacket service '%s' is not allowed to authorize\n", packet->service);
-    packet->packetType = RAD_REJECT_PACKET;
-    return 0;
-    }
+    sigset_t signalSet;
+    sigfillset(&signalSet);
+    pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
 
-if (store->RestoreUserConf(&conf, (char *)packet->login))
-    {
-    packet->packetType = RAD_REJECT_PACKET;
-    printfd(__FILE__, "RADIUS::ProcessAutzPacket cannot restore conf for user '%s'\n", packet->login);
-    return 0;
-    }
+    static_cast<RADIUS *>(d)->runImpl();
 
-// At this point service can be authorized at least
-// So we send a plain-text password
-
-packet->packetType = RAD_ACCEPT_PACKET;
-strncpy((char *)packet->password, conf.password.c_str(), RAD_PASSWORD_LEN);
-
-return 0;
+    return NULL;
 }
-//-----------------------------------------------------------------------------
-int RADIUS::ProcessAuthPacket(RAD_PACKET * packet)
-{
-USER_PTR ui;
-
-if (!CanAcctService((char *)packet->service))
-    {
-
-    // There are no sense to check for allowed service
-    // It has allready checked at previous stage (authorization)
-
-    printfd(__FILE__, "RADIUS::ProcessAuthPacket service '%s' neednot stargazer authentication\n", (char *)packet->service);
-    packet->packetType = RAD_ACCEPT_PACKET;
-    return 0;
-    }
 
-// At this point we have an accountable service
-// All other services got a password if allowed or rejected
-
-if (!FindUser(&ui, (char *)packet->login))
-    {
-    packet->packetType = RAD_REJECT_PACKET;
-    printfd(__FILE__, "RADIUS::ProcessAuthPacket user '%s' not found\n", (char *)packet->login);
-    return 0;
-    }
-
-if (ui->IsInetable())
-    {
-    packet->packetType = RAD_ACCEPT_PACKET;
-    }
-else
-    {
-    packet->packetType = RAD_REJECT_PACKET;
-    }
-
-packet->packetType = RAD_ACCEPT_PACKET;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int RADIUS::ProcessPostAuthPacket(RAD_PACKET * packet)
+void RADIUS::runImpl()
 {
-USER_PTR ui;
-
-if (!CanAcctService((char *)packet->service))
-    {
+    m_running = true;
 
-    // There are no sense to check for allowed service
-    // It has allready checked at previous stage (authorization)
-
-    packet->packetType = RAD_ACCEPT_PACKET;
-    return 0;
-    }
-
-if (!FindUser(&ui, (char *)packet->login))
-    {
-    packet->packetType = RAD_REJECT_PACKET;
-    printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", (char *)packet->login);
-    return 0;
-    }
-
-// I think that only Framed-User services has sense to be accountable
-// So we have to supply a Framed-IP
-
-USER_IPS ips = ui->GetProperty().ips;
-packet->packetType = RAD_ACCEPT_PACKET;
-
-// Additional checking for Framed-User service
-
-if (!strncmp((char *)packet->service, "Framed-User", RAD_SERVICE_LEN))
-    packet->ip = ips[0].ip;
-else
-    packet->ip = 0;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int RADIUS::ProcessAcctStartPacket(RAD_PACKET * packet)
-{
-USER_PTR ui;
+    while (m_running) {
+        fd_set fds;
 
-if (!FindUser(&ui, (char *)packet->login))
-    {
-    packet->packetType = RAD_REJECT_PACKET;
-    printfd(__FILE__, "RADIUS::ProcessAcctStartPacket user '%s' not found\n", (char *)packet->login);
-    return 0;
-    }
+        buildFDSet(fds);
 
-// At this point we have to unauthorize user only if it is an accountable service
+        struct timeval tv;
+        tv.tv_sec = 0;
+        tv.tv_usec = 500000;
 
-if (CanAcctService((char *)packet->service))
-    {
-    if (sessions.find((const char *)packet->sessid) != sessions.end())
+        int res = select(maxFD() + 1, &fds, NULL, NULL, &tv);
+        if (res < 0)
         {
-        printfd(__FILE__, "RADIUS::ProcessAcctStartPacket session already started!\n");
-        packet->packetType = RAD_REJECT_PACKET;
-        return -1;
-        }
-    USER_IPS ips = ui->GetProperty().ips;
-    if (!users->Authorize(ui->GetLogin(), ips[0].ip, 0xffFFffFF, this))
-        {
-        printfd(__FILE__, "RADIUS::ProcessAcctStartPacket cannot authorize user '%s'\n", packet->login);
-        packet->packetType = RAD_REJECT_PACKET;
-        return -1;
+            m_error = std::string("'select' is failed: '") + strerror(errno) + "'.";
+            m_logger(m_error);
+            break;
         }
-    sessions[(const char *)packet->sessid].userName = (const char *)packet->login;
-    sessions[(const char *)packet->sessid].serviceType = (const char *)packet->service;
-    for_each(sessions.begin(), sessions.end(), SPrinter());
-    }
-else
-    {
-    printfd(__FILE__, "RADIUS::ProcessAcctStartPacket service '%s' can not be accounted\n", (char *)packet->service);
-    }
-
-packet->packetType = RAD_ACCEPT_PACKET;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int RADIUS::ProcessAcctStopPacket(RAD_PACKET * packet)
-{
-std::map<std::string, RAD_SESSION>::iterator sid;
 
-if ((sid = sessions.find((const char *)packet->sessid)) == sessions.end())
-    {
-    printfd(__FILE__, "RADIUS::ProcessAcctStopPacket session had not started yet\n");
-    packet->packetType = RAD_REJECT_PACKET;
-    return -1;
-    }
+        if (!m_running)
+            break;
 
-USER_PTR ui;
+        if (res > 0)
+            handleEvents(fds);
 
-if (!FindUser(&ui, sid->second.userName))
-    {
-    packet->packetType = RAD_REJECT_PACKET;
-    printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", sid->second.userName.c_str());
-    return 0;
+        cleanupConns();
     }
 
-sessions.erase(sid);
-
-users->Unauthorize(ui->GetLogin(), this);
-
-packet->packetType = RAD_ACCEPT_PACKET;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int RADIUS::ProcessAcctUpdatePacket(RAD_PACKET * packet)
-{
-// Fake. May be use it later
-packet->packetType = RAD_ACCEPT_PACKET;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int RADIUS::ProcessAcctOtherPacket(RAD_PACKET * packet)
-{
-// Fake. May be use it later
-packet->packetType = RAD_ACCEPT_PACKET;
-return 0;
+    m_stopped = true;
 }
-//-----------------------------------------------------------------------------
-bool RADIUS::FindUser(USER_PTR * ui, const std::string & login) const
-{
-if (users->FindByName(login, ui))
-    {
-    return false;
-    }
-return true;
-}
-//-----------------------------------------------------------------------------
-bool RADIUS::CanAuthService(const std::string & svc) const
-{
-return find(authServices.begin(), authServices.end(), svc) != authServices.end();
-}
-//-----------------------------------------------------------------------------
-bool RADIUS::CanAcctService(const std::string & svc) const
-{
-return find(acctServices.begin(), acctServices.end(), svc) != acctServices.end();
-}
-//-----------------------------------------------------------------------------
-bool RADIUS::IsAllowedService(const std::string & svc) const
+
+int RADIUS::maxFD() const
 {
-return CanAuthService(svc) || CanAcctService(svc);
+    int maxFD = m_listenSocket;
+    std::deque<STG::Conn *>::const_iterator it;
+    for (it = m_conns.begin(); it != m_conns.end(); ++it)
+        if (maxFD < (*it)->sock())
+            maxFD = (*it)->sock();
+    return maxFD;
 }
-//-----------------------------------------------------------------------------
-namespace
-{
 
-inline
-void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password)
+void RADIUS::buildFDSet(fd_set & fds) const
 {
-unsigned char keyL[RAD_PASSWORD_LEN];  // Пароль для шифровки
-memset(keyL, 0, RAD_PASSWORD_LEN);
-strncpy((char *)keyL, password.c_str(), RAD_PASSWORD_LEN);
-Blowfish_Init(ctx, keyL, RAD_PASSWORD_LEN);
+    FD_ZERO(&fds);
+    FD_SET(m_listenSocket, &fds);
+    std::deque<STG::Conn *>::const_iterator it;
+    for (it = m_conns.begin(); it != m_conns.end(); ++it)
+        FD_SET((*it)->sock(), &fds);
 }
-//-----------------------------------------------------------------------------
-inline
-void Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8)
-{
-// len8 - длина в 8-ми байтовых блоках
-if (dst != src)
-    memcpy(dst, src, len8 * 8);
 
-for (size_t i = 0; i < len8; i++)
-    Blowfish_Encrypt(ctx, static_cast<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
-}
-//-----------------------------------------------------------------------------
-inline
-void Decrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8)
+void RADIUS::cleanupConns()
 {
-// len8 - длина в 8-ми байтовых блоках
-if (dst != src)
-    memcpy(dst, src, len8 * 8);
+    std::deque<STG::Conn *>::iterator pos;
+    for (pos = m_conns.begin(); pos != m_conns.end(); ++pos)
+        if (((*pos)->isDone() && !(*pos)->isKeepAlive()) || !(*pos)->isOk()) {
+            delete *pos;
+            *pos = NULL;
+        }
 
-for (size_t i = 0; i < len8; i++)
-    Blowfish_Decrypt(ctx, static_cast<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
+    pos = std::remove(m_conns.begin(), m_conns.end(), static_cast<STG::Conn *>(NULL));
+    m_conns.erase(pos, m_conns.end());
 }
 
-} // namespace anonymous
+void RADIUS::handleEvents(const fd_set & fds)
+{
+    if (FD_ISSET(m_listenSocket, &fds))
+        acceptConnection();
+    else
+    {
+        std::deque<STG::Conn *>::iterator it;
+        for (it = m_conns.begin(); it != m_conns.end(); ++it)
+            if (FD_ISSET((*it)->sock(), &fds))
+                (*it)->read();
+    }
+}
index 8f5ba2a451ad8ad3d88dcb88fd0ae7f5013ffe3c..ff8ecf5e08410839cf5ab08fad3396bf5110afd7 100644 (file)
  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
-/*
- *  Radius data access plugin for Stargazer
- *
- *  $Revision: 1.10 $
- *  $Date: 2009/12/13 14:17:13 $
- *
- */
-
-#ifndef RADIUS_H
-#define RADIUS_H
-
-#include <pthread.h>
-
-#include <cstring>
-#include <cstdlib>
-#include <string>
-#include <list>
-#include <map>
-#include <vector>
+#ifndef __STG_RADIUS_H__
+#define __STG_RADIUS_H__
 
 #include "stg/os_int.h"
 #include "stg/auth.h"
 #include "stg/module_settings.h"
-#include "stg/notifer.h"
-#include "stg/user_ips.h"
-#include "stg/user.h"
-#include "stg/users.h"
-#include "stg/blowfish.h"
-#include "stg/rad_packets.h"
 #include "stg/logger.h"
 
-extern "C" PLUGIN * GetPlugin();
+#include <string>
 
-#define RAD_DEBUG (1)
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/types.h>
 
-class RADIUS;
-//-----------------------------------------------------------------------------
-class RAD_SETTINGS {
-public:
-    RAD_SETTINGS()
-        : port(0), errorStr(), password(),
-          authServices(), acctServices()
-    {}
-    virtual ~RAD_SETTINGS() {}
-    const std::string & GetStrError() const { return errorStr; }
-    int ParseSettings(const MODULE_SETTINGS & s);
-    uint16_t GetPort() const { return port; }
-    const std::string & GetPassword() const { return password; }
-    const std::list<std::string> & GetAuthServices() const { return authServices; }
-    const std::list<std::string> & GetAcctServices() const { return acctServices; }
+extern "C" PLUGIN * GetPlugin();
 
-private:
-    int ParseServices(const std::vector<std::string> & str, std::list<std::string> * lst);
+class STORE;
+class USERS;
 
-    uint16_t port;
-    std::string errorStr;
-    std::string password;
-    std::list<std::string> authServices;
-    std::list<std::string> acctServices;
-};
-//-----------------------------------------------------------------------------
-struct RAD_SESSION {
-    RAD_SESSION() : userName(), serviceType() {}
-    std::string userName;
-    std::string serviceType;
-};
-//-----------------------------------------------------------------------------
-class RADIUS :public AUTH {
+class RADIUS : public AUTH {
 public:
-                        RADIUS();
-    virtual             ~RADIUS() {}
+    RADIUS();
+    virtual ~RADIUS() {}
 
-    void                SetUsers(USERS * u) { users = u; }
-    void                SetStore(STORE * s) { store = s; }
-    void                SetStgSettings(const SETTINGS *) {}
-    void                SetSettings(const MODULE_SETTINGS & s) { settings = s; }
-    int                 ParseSettings();
+    void SetUsers(USERS* u) { users = u; }
+    void SetStore(STORE* s) { store = s; }
+    void SetStgSettings(const SETTINGS*) {}
+    void SetSettings(const MODULE_SETTINGS& s) { settings = s; }
+    int ParseSettings();
 
-    int                 Start();
-    int                 Stop();
-    int                 Reload() { return 0; }
-    bool                IsRunning() { return isRunning; }
+    int Start();
+    int Stop();
+    int Reload() { return 0; }
+    bool IsRunning() { return m_running; }
 
-    const std::string & GetStrError() const { return errorStr; }
-    std::string         GetVersion() const { return "RADIUS data access plugin v 0.6"; }
-    uint16_t            GetStartPosition() const { return 30; }
-    uint16_t            GetStopPosition() const { return 30; }
+    const std::string& GetStrError() const { return m_error; }
+    std::string GetVersion() const { return "RADIUS data access plugin v 1.0"; }
+    uint16_t GetStartPosition() const { return 30; }
+    uint16_t GetStopPosition() const { return 30; }
 
-    int SendMessage(const STG_MSG &, uint32_t) const { return 0; }
+    int SendMessage(const STG_MSG&, uint32_t) const { return 0; }
 
 private:
     RADIUS(const RADIUS & rvalue);
     RADIUS & operator=(const RADIUS & rvalue);
 
-    static void *       Run(void *);
-    int                 PrepareNet();
-    int                 FinalizeNet();
-
-    ssize_t             Send(const RAD_PACKET & packet, struct sockaddr_in * outerAddr);
-    int                 RecvData(RAD_PACKET * packet, struct sockaddr_in * outerAddr);
-    int                 ProcessData(RAD_PACKET * packet);
-
-    int                 ProcessAutzPacket(RAD_PACKET * packet);
-    int                 ProcessAuthPacket(RAD_PACKET * packet);
-    int                 ProcessPostAuthPacket(RAD_PACKET * packet);
-    int                 ProcessAcctStartPacket(RAD_PACKET * packet);
-    int                 ProcessAcctStopPacket(RAD_PACKET * packet);
-    int                 ProcessAcctUpdatePacket(RAD_PACKET * packet);
-    int                 ProcessAcctOtherPacket(RAD_PACKET * packet);
-
-    bool                FindUser(USER_PTR * ui, const std::string & login) const;
-    bool                CanAuthService(const std::string & svc) const;
-    bool                CanAcctService(const std::string & svc) const;
-    bool                IsAllowedService(const std::string & svc) const;
-
-    struct SPrinter : public std::unary_function<std::pair<std::string, RAD_SESSION>, void>
-    {
-        void operator()(const std::pair<std::string, RAD_SESSION> & it)
-        {
-            printfd("radius.cpp", "%s - ('%s', '%s')\n", it.first.c_str(), it.second.userName.c_str(), it.second.serviceType.c_str());
-        }
-    };
-
-    BLOWFISH_CTX        ctx;
+    static void* run(void*);
 
-    mutable std::string errorStr;
-    RAD_SETTINGS        radSettings;
-    MODULE_SETTINGS     settings;
-    std::list<std::string> authServices;
-    std::list<std::string> acctServices;
-    std::map<std::string, RAD_SESSION> sessions;
+    void rumImpl();
+    int maxFD() const;
+    void buildFDSet(fd_set & fds) const;
+    void cleanupConns();
+    void handleEvents(const fd_set & fds);
+    void acceptConnection();
 
-    bool                nonstop;
-    bool                isRunning;
+    mutable std::string m_error;
+    STG::Config m_config;
 
-    USERS *             users;
-    const SETTINGS *    stgSettings;
-    const STORE *       store;
+    MODULE_SETTINGS m_settings;
 
-    pthread_t           thread;
-    pthread_mutex_t     mutex;
+    bool m_running;
+    bool m_stopped;
 
-    int                 sock;
+    USERS* m_users;
+    const STORE* m_store;
 
-    RAD_PACKET          packet;
+    pthread_t m_thread;
+    pthread_mutex_t m_mutex;
 
-    PLUGIN_LOGGER       logger;
+    PLUGIN_LOGGER m_logger;
 };
-//-----------------------------------------------------------------------------
 
 #endif
diff --git a/projects/stargazer/plugins/other/radius/reader.cpp b/projects/stargazer/plugins/other/radius/reader.cpp
new file mode 100644 (file)
index 0000000..e7d3e2f
--- /dev/null
@@ -0,0 +1,7 @@
+#include "reader.h"
+
+using STG::Reader;
+
+Reader::Reader()
+{
+}
diff --git a/projects/stargazer/plugins/other/radius/reader.h b/projects/stargazer/plugins/other/radius/reader.h
new file mode 100644 (file)
index 0000000..3bc1f9e
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONFIG_READER_H__
+#define __STG_SGCONFIG_READER_H__
+
+#include <string>
+#include <vector>
+#include <utility>
+
+namespace STG
+{
+
+struct BaseReader
+{
+    virtual ~BaseReader() {}
+
+    virtual ssize_t read(TransportProto& proto) = 0;
+    virtual bool done() const = 0;
+};
+
+template <typename T>
+class Reader : public BaseReader
+{
+    public:
+        Reader(size_t size = sizeof(T)) : m_size(size), m_done(0) {}
+
+        virtual ssize_t read(TransportProto& proto)
+        {
+            char* pos = static_cast<void*>(&m_dest);
+            pos += m_done;
+            ssize_t res = proto.read(pos, m_size - m_done);
+            if (res < 0)
+                return res;
+            if (res == 0) {
+                m_done = m_size;
+                return 0;
+            }
+            m_done += res;
+            return res;
+        }
+
+        virtual bool done() const { return m_done == m_size; }
+
+        T get() const { return ntoh(m_dest); }
+
+    private:
+        T m_dest;
+        size_t m_size;
+        size_t m_done;
+
+};
+
+template <>
+class Reader<std::vector<Reader*> > : public BaseReader
+{
+    public:
+        Reader(const std::vector<Reader*>& readers) : m_size(readers.size()), m_done(0) {}
+
+        virtual ssize_t read(TransportProto& proto)
+        {
+            if (m_size == 0)
+                return 0;
+            size_t res = m_dest[m_done]->read(proto);
+            if (res < 0)
+                return res;
+            if (res == 0) {
+                m_done = m_size;
+                return 0;
+            }
+            if (m_dest[m_done].done())
+                ++m_dest;
+            return res;
+        }
+
+        virtual bool done() const { return m_done == m_size; }
+
+        const T& get() const { return m_dest; }
+
+    private:
+        T m_dest;
+        size_t m_size;
+        size_t m_done;
+
+};
+
+template <>
+class Reader<std::vector<char> > : public BaseReader
+{
+    public:
+        Reader(size_t size ) : m_dest(size), m_size(size), m_done(0) {}
+
+        virtual ssize_t read(TransportProto& proto)
+        {
+            char* pos = static_cast<void*>(m_dest.data());
+            pos += m_done;
+            ssize_t res = proto.read(pos, m_size - m_done);
+            if (res < 0)
+                return res;
+            if (res == 0) {
+                m_done = m_size;
+                return 0;
+            }
+            m_done += res;
+            return res;
+        }
+
+        virtual bool done() const { return m_done == m_size; }
+
+        const std::vector<char>& get() const { return m_dest; }
+
+    private:
+        std::vector<char> m_dest;
+        size_t m_size;
+        size_t m_done;
+
+};
+
+template <>
+class Reader<std::string>
+{
+    public:
+        Reader() : m_dest(Reader<std::string>::initDest()) {}
+
+        virtual ssize_t read(TransportProto& proto)
+        {
+            if (m_size == 0)
+                return 0;
+            size_t res = m_dest[m_done]->read(proto);
+            if (res < 0)
+                return res;
+            if (res == 0) {
+                m_done = m_size;
+                return 0;
+            }
+            if (m_dest[m_done].done())
+                ++m_dest;
+            return res;
+        }
+
+        virtual bool done() const { return m_done == m_size; }
+
+        const T& get() const { return m_dest; }
+
+    private:
+        T m_dest;
+        size_t m_size;
+        size_t m_done;
+};
+
+} // namespace STG
+
+#endif
index 1f662c25c3357985ec83d49a11fbb5129b7a4539..932e270948b62d3b78fed5186e6889e53dd304b2 100644 (file)
@@ -7,9 +7,11 @@ include ../../Makefile.conf
 LIB_NAME = stgcommon
 
 SRCS = common.cpp \
-       strptime.cpp
+       strptime.cpp \
+       blockio.cpp
 
-INCS = common.h
+INCS = common.h \
+       blockio.h
 
 LIBS += $(LIBICONV)
 
diff --git a/stglibs/common.lib/blockio.cpp b/stglibs/common.lib/blockio.cpp
new file mode 100644 (file)
index 0000000..04fd1d8
--- /dev/null
@@ -0,0 +1,102 @@
+#include "stg/blockio.h"
+
+namespace
+{
+
+void* adjust(void* base, size_t shift)
+{
+    char* ptr = static_cast<char*>(base);
+    return ptr + shift;
+}
+
+} // namspace anonymous
+
+using STG::BlockReader;
+using STG::BlockWriter;
+
+BlockReader::BlockReader(const IOVec& ioVec)
+    : m_dest(ioVec),
+      m_remainder(0)
+{
+    for (size_t i = 0; i < m_dest.size(); ++i)
+        m_remainder += m_dest[i].iov_len;
+}
+
+bool BlockReader::read(int socket)
+{
+    if (m_remainder == 0)
+        return true;
+
+    size_t offset = m_dest.size() - 1;
+    size_t toRead = m_remainder;
+    while (offset > 0) {
+        if (toRead < m_dest[offset].iov_len)
+            break;
+        toRead -= m_dest[offset].iov_len;
+        --offset;
+    }
+
+    IOVec dest(m_dest.size() - offset);
+    for (size_t i = 0; i < dest.size(); ++i) {
+        if (i == 0) {
+            dest[0].iov_len = toRead;
+            dest[0].iov_base = adjust(m_dest[offset].iov_base, m_dest[offset].iov_len - toRead);
+        } else {
+            dest[i] = m_dest[offset + i];
+        }
+    }
+
+    ssize_t res = readv(socket, dest.data(), dest.size());
+    if (res < 0)
+        return false;
+    if (res == 0)
+        return m_remainder == 0;
+    if (res < static_cast<ssize_t>(m_remainder))
+        m_remainder -= res;
+    else
+        m_remainder = 0;
+    return true;
+}
+
+BlockWriter::BlockWriter(const IOVec& ioVec)
+    : m_source(ioVec),
+      m_remainder(0)
+{
+    for (size_t i = 0; i < m_source.size(); ++i)
+        m_remainder += m_source[i].iov_len;
+}
+
+bool BlockWriter::write(int socket)
+{
+    if (m_remainder == 0)
+        return true;
+
+    size_t offset = m_source.size() - 1;
+    size_t toWrite = m_remainder;
+    while (offset > 0) {
+        if (toWrite < m_source[offset].iov_len)
+            break;
+        toWrite -= m_source[offset].iov_len;
+        --offset;
+    }
+
+    IOVec source(m_source.size() - offset);
+    for (size_t i = 0; i < source.size(); ++i) {
+        if (i == 0) {
+            source[0].iov_len = toWrite;
+            source[0].iov_base = adjust(m_source[offset].iov_base, m_source[offset].iov_len - toWrite);
+        } else {
+            source[i] = m_source[offset + i];
+        }
+    }
+    ssize_t res = writev(socket, source.data(), source.size());
+    if (res < 0)
+        return false;
+    if (res == 0)
+        return m_remainder == 0;
+    if (res < static_cast<ssize_t>(m_remainder))
+        m_remainder -= res;
+    else
+        m_remainder = 0;
+    return true;
+}
diff --git a/stglibs/common.lib/include/stg/blockio.h b/stglibs/common.lib/include/stg/blockio.h
new file mode 100644 (file)
index 0000000..3879e39
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __STG_STGLIBS_BLOCK_IO_H__
+#define __STG_STGLIBS_BLOCK_IO_H__
+
+#include <vector>
+
+#include <sys/uio.h>
+
+namespace STG
+{
+
+typedef std::vector<iovec> IOVec;
+
+class BlockReader
+{
+    public:
+        BlockReader(const IOVec& ioVec);
+
+        bool read(int socket);
+        bool done() const { return m_remainder == 0; }
+        size_t remainder() const { return m_remainder; }
+
+    private:
+        IOVec m_dest;
+        size_t m_remainder;
+};
+
+class BlockWriter
+{
+    public:
+        BlockWriter(const IOVec& ioVec);
+
+        bool write(int socket);
+        bool done() const { return m_remainder == 0; }
+        size_t remainder() const { return m_remainder; }
+
+    private:
+        IOVec m_source;
+        size_t m_remainder;
+};
+
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/Makefile b/stglibs/sgcp.lib/Makefile
new file mode 100644 (file)
index 0000000..01ec337
--- /dev/null
@@ -0,0 +1,16 @@
+include ../../Makefile.conf
+
+LIB_NAME = stgsgcp
+
+SRCS = proto.cpp \
+       transport.cpp \
+       unix.cpp \
+       udp.cpp \
+       tcp.cpp \
+       crypto.cpp
+
+INCS = sgcp_proto.h \
+       sgcp_types.h \
+       sgcp_transport.h
+
+include ../Makefile.in
diff --git a/stglibs/sgcp.lib/crypto.cpp b/stglibs/sgcp.lib/crypto.cpp
new file mode 100644 (file)
index 0000000..2b2bb8f
--- /dev/null
@@ -0,0 +1,30 @@
+#include "crypto.h"
+
+using STG::SGCP::CryptoProto;
+
+CryptoProto::CryptoProto(const std::string& key, TransportProto* underlying)
+    : m_underlying(underlying)
+{
+}
+
+CryptoProto::~CryptoProto()
+{
+    delete m_underlying;
+}
+
+void CryptoProto::connect(const std::string& address, uint16_t port)
+{
+    m_underlying->connect(address, port);
+}
+
+ssize_t CryptoProto::write(const void* buf, size_t size)
+{
+    // TODO: to implement
+    return m_underlying->write(buf, size);
+}
+
+ssize_t CryptoProto::read(void* buf, size_t size)
+{
+    // TODO: to implement
+    return m_underlying->read(buf, size);
+}
diff --git a/stglibs/sgcp.lib/crypto.h b/stglibs/sgcp.lib/crypto.h
new file mode 100644 (file)
index 0000000..5f720d0
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __STG_SGCP_CRYPTO_H__
+#define __STG_SGCP_CRYPTO_H__
+
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_transport.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+
+#include <unistd.h> // ssize_t
+
+namespace STG
+{
+namespace SGCP
+{
+
+class CryptoProto : public TransportProto
+{
+    public:
+        CryptoProto(const std::string& key, TransportProto* underlying);
+        virtual ~CryptoProto();
+
+        virtual void connect(const std::string& address, uint16_t port);
+        virtual ssize_t write(const void* buf, size_t size);
+        virtual ssize_t read(void* buf, size_t size);
+
+    private:
+        TransportProto* m_underlying;
+};
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/include/stg/sgcp_proto.h b/stglibs/sgcp.lib/include/stg/sgcp_proto.h
new file mode 100644 (file)
index 0000000..3cc35b1
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef __STG_SGCP_PROTO_H__
+#define __STG_SGCP_PROTO_H__
+
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "sgcp_types.h" // TransportType
+#include "sgcp_utils.h" // hton/ntoh
+
+#include "stg/os_int.h"
+
+#include <string>
+#include <vector>
+#include <stdexcept>
+
+namespace STG
+{
+namespace SGCP
+{
+
+class TransportProto;
+
+class Proto
+{
+    public:
+        struct Error : public std::runtime_error
+        {
+            Error(const std::string& mesage);
+            Error();
+        };
+
+        Proto(TransportType transport, const std::string& key);
+        ~Proto();
+
+        void connect(const std::string& address, uint16_t port);
+
+        void writeAllBuf(const void* buf, size_t size);
+        void readAllBuf(void* buf, size_t size);
+
+        template <typename T>
+        void writeAll(const T& value);
+
+        template <typename T>
+        T readAll();
+
+    private:
+        TransportProto* m_transport;
+};
+
+template <>
+inline
+void Proto::writeAll<uint64_t>(const uint64_t& value)
+{
+    uint64_t temp = hton(value);
+    writeAllBuf(&temp, sizeof(temp));
+}
+
+template <>
+inline
+void Proto::writeAll<std::string>(const std::string& value)
+{
+    uint64_t size = hton(value.size());
+    writeAllBuf(&size, sizeof(size));
+    writeAllBuf(value.c_str(), value.size());
+}
+
+template <>
+inline
+uint64_t Proto::readAll<uint64_t>()
+{
+    uint64_t temp = 0;
+    readAllBuf(&temp, sizeof(temp));
+    return ntoh(temp);
+}
+
+template <>
+inline
+std::string Proto::readAll<std::string>()
+{
+    uint64_t size = 0;
+    readAllBuf(&size, sizeof(size));
+    size = ntoh(size);
+    std::vector<char> res(size);
+    readAllBuf(res.data(), res.size());
+    return res.data();
+}
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/include/stg/sgcp_transport.h b/stglibs/sgcp.lib/include/stg/sgcp_transport.h
new file mode 100644 (file)
index 0000000..88a7d0c
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __STG_SGCP_TRANSPORT_H__
+#define __STG_SGCP_TRANSPORT_H__
+
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_types.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+#include <stdexcept>
+
+#include <unistd.h> // ssize_t
+
+namespace STG
+{
+namespace SGCP
+{
+
+class TransportProto
+{
+    public:
+        struct Error : public std::runtime_error {
+            Error(const std::string& message) : runtime_error(message) {}
+        };
+
+        static TransportProto* create(TransportType transport, const std::string& key);
+        static TransportProto* create(TransportType transport);
+
+        virtual ~TransportProto() {}
+
+        virtual void connect(const std::string& address, uint16_t port) = 0;
+        virtual ssize_t write(const void* buf, size_t size) = 0;
+        virtual ssize_t read(void* buf, size_t size) = 0;
+};
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/include/stg/sgcp_types.h b/stglibs/sgcp.lib/include/stg/sgcp_types.h
new file mode 100644 (file)
index 0000000..4792007
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __STG_SGCP_TYPES_H__
+#define __STG_SGCP_TYPES_H__
+
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+namespace STG
+{
+namespace SGCP
+{
+
+enum TransportType
+{
+    UNIX,
+    UDP,
+    TCP
+};
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/include/stg/sgcp_utils.h b/stglibs/sgcp.lib/include/stg/sgcp_utils.h
new file mode 100644 (file)
index 0000000..7e5004c
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __STG_SGCP_UTILS_H__
+#define __STG_SGCP_UTILS_H__
+
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "stg/os_int.h"
+
+#include <string>
+#include <vector>
+
+#include <arpa/inet.h> // hton*
+#include <netinet/in.h> // in_addr
+
+namespace STG
+{
+namespace SGCP
+{
+
+template <typename T> inline T hton(T value) { return value; }
+template <typename T> inline T ntoh(T value) { return hton(value); }
+
+template <> inline uint16_t hton(uint16_t value) { return htons(value); }
+template <> inline int16_t hton(int16_t value) { return htons(value); }
+
+template <> inline uint32_t hton(uint32_t value) { return htonl(value); }
+template <> inline int32_t hton(int32_t value) { return htonl(value); }
+
+inline
+uint64_t htonll(uint64_t value)
+{
+#ifdef ARCH_LE
+    const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
+    const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));
+
+    return (static_cast<uint64_t>(low_part) << 32) | high_part;
+#else
+    return value;
+#endif
+}
+
+template <> inline uint64_t hton(uint64_t value) { return htonll(value); }
+template <> inline int64_t hton(int64_t value) { return htonll(value); }
+
+std::vector<in_addr> resolve(const std::string& address);
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/proto.cpp b/stglibs/sgcp.lib/proto.cpp
new file mode 100644 (file)
index 0000000..96b6285
--- /dev/null
@@ -0,0 +1,63 @@
+#include "stg/sgcp_proto.h"
+
+#include "stg/sgcp_transport.h"
+
+#include <cstring>
+#include <cerrno>
+
+using STG::SGCP::Proto;
+
+Proto::Error::Error(const std::string& message)
+    : runtime_error(message)
+{}
+
+Proto::Error::Error()
+    : runtime_error(strerror(errno))
+{}
+
+Proto::Proto(TransportType transport, const std::string& key)
+    : m_transport(TransportProto::create(transport, key))
+{
+}
+
+Proto::~Proto()
+{
+    delete m_transport;
+}
+
+void Proto::connect(const std::string& address, uint16_t port)
+{
+    try {
+        m_transport->connect(address, port);
+    } catch (const TransportProto::Error& ex) {
+        throw Error(ex.what());
+    }
+}
+
+void Proto::writeAllBuf(const void* buf, size_t size)
+{
+    const char* pos = static_cast<const char*>(buf);
+    while (size > 0) {
+        ssize_t res = m_transport->write(pos, size);
+        if (res < 0)
+            throw Error();
+        if (res == 0)
+            return;
+        size -= res;
+        pos += res;
+    }
+}
+
+void Proto::readAllBuf(void* buf, size_t size)
+{
+    char* pos = static_cast<char*>(buf);
+    while (size > 0) {
+        ssize_t res = m_transport->read(pos, size);
+        if (res < 0)
+            throw Error();
+        if (res == 0)
+            return;
+        size -= res;
+        pos += res;
+    }
+}
diff --git a/stglibs/sgcp.lib/tcp.cpp b/stglibs/sgcp.lib/tcp.cpp
new file mode 100644 (file)
index 0000000..414d5ec
--- /dev/null
@@ -0,0 +1,52 @@
+#include "tcp.h"
+
+#include "stg/sgcp_utils.h"
+
+#include <cerrno>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+using STG::SGCP::TCPProto;
+
+TCPProto::TCPProto()
+    : m_sock(socket(AF_INET, SOCK_STREAM, 0))
+{
+}
+
+TCPProto::~TCPProto()
+{
+    close(m_sock);
+}
+
+void TCPProto::connect(const std::string& address, uint16_t port)
+{
+    std::vector<in_addr> addrs = resolve(address);
+
+    for (size_t i = 0; i < addrs.size(); ++i) {
+        sockaddr_in addr;
+        addr.sin_family = AF_INET;
+        addr.sin_port = hton(port);
+        addr.sin_addr = addrs[i];
+
+        if (::connect(m_sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == 0)
+            return;
+
+        close(m_sock);
+        m_sock = socket(AF_INET, SOCK_STREAM, 0);
+    }
+    throw Error("No more addresses to connect to.");
+}
+
+ssize_t TCPProto::write(const void* buf, size_t size)
+{
+    return ::write(m_sock, buf, size);
+}
+
+ssize_t TCPProto::read(void* buf, size_t size)
+{
+    return ::read(m_sock, buf, size);
+}
diff --git a/stglibs/sgcp.lib/tcp.h b/stglibs/sgcp.lib/tcp.h
new file mode 100644 (file)
index 0000000..8afa0b5
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __STG_SGCP_TCP_H__
+#define __STG_SGCP_TCP_H__
+
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_transport.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+
+#include <unistd.h> // ssize_t
+
+namespace STG
+{
+namespace SGCP
+{
+
+class TCPProto : public TransportProto
+{
+    public:
+        TCPProto();
+        virtual ~TCPProto();
+
+        virtual void connect(const std::string& address, uint16_t port);
+        virtual ssize_t write(const void* buf, size_t size);
+        virtual ssize_t read(void* buf, size_t size);
+
+    private:
+        int m_sock;
+};
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/transport.cpp b/stglibs/sgcp.lib/transport.cpp
new file mode 100644 (file)
index 0000000..1e94fa5
--- /dev/null
@@ -0,0 +1,27 @@
+#include "stg/sgcp_transport.h"
+
+#include "crypto.h"
+#include "unix.h"
+#include "udp.h"
+#include "tcp.h"
+
+using STG::SGCP::TransportProto;
+
+TransportProto* TransportProto::create(TransportType transport, const std::string& key)
+{
+    TransportProto* underlying = create(transport);
+    if (key.empty())
+        return underlying;
+    else
+        return new CryptoProto(key, underlying);
+}
+
+TransportProto* TransportProto::create(TransportType transport)
+{
+    switch (transport) {
+        case UNIX: return new UnixProto;
+        case UDP: return new UDPProto;
+        case TCP: return new TCPProto;
+    };
+    return NULL;
+}
diff --git a/stglibs/sgcp.lib/udp.cpp b/stglibs/sgcp.lib/udp.cpp
new file mode 100644 (file)
index 0000000..ebbb98e
--- /dev/null
@@ -0,0 +1,52 @@
+#include "udp.h"
+
+#include "stg/sgcp_utils.h"
+
+#include <cerrno>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/udp.h>
+
+using STG::SGCP::UDPProto;
+
+UDPProto::UDPProto()
+    : m_sock(socket(AF_INET, SOCK_DGRAM, 0))
+{
+}
+
+UDPProto::~UDPProto()
+{
+    close(m_sock);
+}
+
+void UDPProto::connect(const std::string& address, uint16_t port)
+{
+    std::vector<in_addr> addrs = resolve(address);
+
+    for (size_t i = 0; i < addrs.size(); ++i) {
+        sockaddr_in addr;
+        addr.sin_family = AF_INET;
+        addr.sin_port = hton(port);
+        addr.sin_addr = addrs[i];
+
+        if (::connect(m_sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == 0)
+            return;
+
+        close(m_sock);
+        m_sock = socket(AF_INET, SOCK_DGRAM, 0);
+    }
+    throw Error("No more addresses to connect to.");
+}
+
+ssize_t UDPProto::write(const void* buf, size_t size)
+{
+    return ::write(m_sock, buf, size);
+}
+
+ssize_t UDPProto::read(void* buf, size_t size)
+{
+    return ::read(m_sock, buf, size);
+}
diff --git a/stglibs/sgcp.lib/udp.h b/stglibs/sgcp.lib/udp.h
new file mode 100644 (file)
index 0000000..b08978b
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __STG_SGCP_UDP_H__
+#define __STG_SGCP_UDP_H__
+
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_transport.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+
+#include <unistd.h> // ssize_t
+
+namespace STG
+{
+namespace SGCP
+{
+
+class UDPProto : public TransportProto
+{
+    public:
+        UDPProto();
+        virtual ~UDPProto();
+
+        virtual void connect(const std::string& address, uint16_t port);
+        virtual ssize_t write(const void* buf, size_t size);
+        virtual ssize_t read(void* buf, size_t size);
+
+    private:
+        int m_sock;
+};
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/unix.cpp b/stglibs/sgcp.lib/unix.cpp
new file mode 100644 (file)
index 0000000..15002e5
--- /dev/null
@@ -0,0 +1,41 @@
+#include "unix.h"
+
+#include <cerrno>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+using STG::SGCP::UnixProto;
+
+UnixProto::UnixProto()
+    : m_sock(socket(AF_UNIX, SOCK_STREAM, 0))
+{
+}
+
+UnixProto::~UnixProto()
+{
+    close(m_sock);
+}
+
+void UnixProto::connect(const std::string& address, uint16_t /*port*/)
+{
+    sockaddr_un addr;
+    addr.sun_family = AF_UNIX;
+    size_t max = sizeof(addr.sun_path);
+    strncpy(addr.sun_path, address.c_str(), max - 1);
+    addr.sun_path[max - 1] = 0; // Just in case.
+    if (::connect(m_sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) < 0)
+        throw Error(strerror(errno));
+}
+
+ssize_t UnixProto::write(const void* buf, size_t size)
+{
+    return ::write(m_sock, buf, size);
+}
+
+ssize_t UnixProto::read(void* buf, size_t size)
+{
+    return ::read(m_sock, buf, size);
+}
diff --git a/stglibs/sgcp.lib/unix.h b/stglibs/sgcp.lib/unix.h
new file mode 100644 (file)
index 0000000..e5b645f
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __STG_SGCP_UNIX_H__
+#define __STG_SGCP_UNIX_H__
+
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_transport.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+
+#include <unistd.h> // ssize_t
+
+namespace STG
+{
+namespace SGCP
+{
+
+class UnixProto : public TransportProto
+{
+    public:
+        UnixProto();
+        virtual ~UnixProto();
+
+        virtual void connect(const std::string& address, uint16_t /*port*/);
+        virtual ssize_t write(const void* buf, size_t size);
+        virtual ssize_t read(void* buf, size_t size);
+
+    private:
+        int m_sock;
+};
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
diff --git a/stglibs/sgcp.lib/utils.cpp b/stglibs/sgcp.lib/utils.cpp
new file mode 100644 (file)
index 0000000..4c33e42
--- /dev/null
@@ -0,0 +1,30 @@
+#include "stg/sgcp_utils.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+std::vector<in_addr> STG::SGCP::resolve(const std::string& address)
+{
+    addrinfo* result = NULL;
+
+    addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+
+    hints.ai_family = AF_INET;    /* Allow IPv4 */
+    hints.ai_socktype = 0; /* Datagram socket */
+    hints.ai_flags = 0;    /* For wildcard IP address */
+    hints.ai_protocol = 0;          /* Any protocol */
+    hints.ai_canonname = NULL;
+    hints.ai_addr = NULL;
+    hints.ai_next = NULL;
+
+    int res = getaddrinfo(address.c_str(), NULL, &hints, &result);
+    if (res != 0)
+        throw TransportProto::Error(gai_error(res));
+
+    std::vector as;
+    for (const addrinfo* p = result; p != NULL; p = p->next)
+        as.push_back(p->ai_addr.sin_addr);
+    return as;
+}