X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsymbian%2Fsilcsymbiannet.cpp;h=c665b3d339632fb6655a6b0484f2e726c1e1def3;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=be658c809c63fb5d606cbbf998584bcdf85611fb;hpb=01f30c58243cbd70424d650e50d8ea30f4ddf0fc;p=silc.git diff --git a/lib/silcutil/symbian/silcsymbiannet.cpp b/lib/silcutil/symbian/silcsymbiannet.cpp index be658c80..c665b3d3 100644 --- a/lib/silcutil/symbian/silcsymbiannet.cpp +++ b/lib/silcutil/symbian/silcsymbiannet.cpp @@ -20,24 +20,69 @@ #include "silc.h" #include "silcsymbiansocketstream.h" +/************************ Static utility functions **************************/ + +static SilcBool silc_net_set_sockaddr(TInetAddr *addr, const char *ip_addr, + int port) +{ + /* Check for IPv4 and IPv6 addresses */ + if (ip_addr) { + if (!silc_net_is_ip(ip_addr)) { + SILC_LOG_ERROR(("%s is not IP address", ip_addr)); + return FALSE; + } + + if (silc_net_is_ip4(ip_addr)) { + /* IPv4 address */ + unsigned char buf[4]; + TUint32 a; + + if (!silc_net_addr2bin(ip_addr, buf, sizeof(buf))) + return FALSE; + + SILC_GET32_MSB(a, buf); + addr->SetAddress(a); + addr->SetPort(port); + } else { +#ifdef HAVE_IPV6 + SILC_LOG_ERROR(("IPv6 not supported")); + return FALSE; +#else + SILC_LOG_ERROR(("Operating System does not support IPv6")); + return FALSE; +#endif + } + } else { + addr->SetAddress(0); + addr->SetPort(port); + } + + return TRUE; +} + /****************************** TCP Listener ********************************/ class SilcSymbianTCPListener; +extern "C" { + /* Deliver new stream to upper layer */ -static void silc_net_accept_stream(SilcSocketStreamStatus status, +static void silc_net_accept_stream(SilcResult status, SilcStream stream, void *context) { SilcNetListener listener = (SilcNetListener)context; - /* In case of error, the socket has been destroyed already */ - if (status != SILC_SOCKET_OK) + /* In case of error, the socket has been destroyed already via + silc_stream_destroy. */ + if (status != SILC_OK) return; - listener->callback(SILC_NET_OK, stream, listener->context); + listener->callback(SILC_OK, stream, listener->context); } +} /* extern "C" */ + /* TCP Listener class */ class SilcSymbianTCPListener : public CActive { @@ -57,6 +102,8 @@ public: /* Listen for connection */ void Listen() { + SILC_LOG_DEBUG(("Listen()")); + new_conn = new RSocket; if (!new_conn) return; @@ -73,6 +120,8 @@ public: /* Listener callback */ virtual void RunL() { + SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus)); + if (iStatus != KErrNone) { if (new_conn) delete new_conn; @@ -81,6 +130,8 @@ public: return; } + SILC_LOG_DEBUG(("Accept new connection")); + /* Set socket options */ new_conn->SetOpt(KSoReuseAddr, KSolInetIp, 1); @@ -111,6 +162,8 @@ public: SilcNetListener listener; }; +extern "C" { + /* Create TCP listener */ SilcNetListener @@ -124,17 +177,26 @@ silc_net_tcp_create_listener(const char **local_ip_addr, SilcSymbianTCPListener *l = NULL; TInetAddr server; TInt ret; - TBuf<64> tmp; int i; SILC_LOG_DEBUG(("Creating TCP listener")); - if (port < 0 || !schedule || !callback) + if (!schedule) { + schedule = silc_schedule_get_global(); + if (!schedule) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + goto err; + } + } + + if (port < 0 || !callback) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); goto err; + } listener = (SilcNetListener)silc_calloc(1, sizeof(*listener)); if (!listener) { - callback(SILC_NET_NO_MEMORY, NULL, context); + callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); return NULL; } listener->schedule = schedule; @@ -145,15 +207,15 @@ silc_net_tcp_create_listener(const char **local_ip_addr, if (local_ip_count > 0) { listener->socks = (SilcSocket *)silc_calloc(local_ip_count, - sizeof(*listener->socks)); + sizeof(*listener->socks)); if (!listener->socks) { - callback(SILC_NET_NO_MEMORY, NULL, context); + callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); return NULL; } } else { listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks)); if (!listener->socks) { - callback(SILC_NET_NO_MEMORY, NULL, context); + callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); return NULL; } @@ -174,42 +236,192 @@ silc_net_tcp_create_listener(const char **local_ip_addr, if (ret != KErrNone) goto err; +#ifdef SILC_THREADS + /* Make our socket shareable between threads */ + l->ss.ShareAuto(); +#endif /* SILC_THREADS */ + /* Set listener address */ - if (local_ip_addr) { - server = TInetAddr(port); - tmp = (TText *)local_ip_addr[i]; - ret = server.Input(tmp); - if (ret != KErrNone) - goto err; - } else { - server = TInetAddr(KInetAddrAny, port); + if (!silc_net_set_sockaddr(&server, local_ip_addr[i], port)) + goto err; + + /* Create the socket */ + ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp); + if (ret != KErrNone) { + SILC_LOG_ERROR(("Cannot create socket, error %d", ret)); + goto err; + } + + /* Set the socket options */ + ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1); + if (ret != KErrNone) { + SILC_LOG_ERROR(("Cannot set socket options, error %d", ret)); + goto err; + } + + /* Bind the listener socket */ + ret = l->sock.Bind(server); + if (ret != KErrNone) { + SILC_LOG_DEBUG(("Cannot bind socket, error %d", ret)); + goto err; + } + + /* Specify that we are listenning */ + ret = l->sock.Listen(5); + if (ret != KErrNone) { + SILC_LOG_ERROR(("Cannot set socket listenning, error %d", ret)); + goto err; + } + l->Listen(); + + l->listener = listener; + listener->socks[i] = (SilcSocket)l; + listener->socks_count++; + } + + SILC_LOG_DEBUG(("TCP listener created")); + + return listener; + + err: + if (l) + delete l; + if (callback) + callback(SILC_ERR, NULL, context); + if (listener) + silc_net_close_listener(listener); + return NULL; +} + +/* Create TCP listener, multiple ports */ + +SilcNetListener +silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports, + SilcUInt32 port_count, + SilcBool ignore_port_error, + SilcBool lookup, SilcBool require_fqdn, + SilcSchedule schedule, + SilcNetCallback callback, void *context) +{ + SilcNetListener listener = NULL; + SilcSymbianTCPListener *l = NULL; + TInetAddr server; + TInt ret; + int i; + + SILC_LOG_DEBUG(("Creating TCP listener")); + + if (!schedule) { + schedule = silc_schedule_get_global(); + if (!schedule) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + goto err; + } + } + + if (!callback) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + goto err; + } + + listener = (SilcNetListener)silc_calloc(1, sizeof(*listener)); + if (!listener) { + callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); + return NULL; + } + listener->schedule = schedule; + listener->callback = callback; + listener->context = context; + listener->require_fqdn = require_fqdn; + listener->lookup = lookup; + + if (port_count > 0) { + listener->socks = (SilcSocket *)silc_calloc(port_count, + sizeof(*listener->socks)); + if (!listener->socks) { + callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); + return NULL; + } + } else { + listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks)); + if (!listener->socks) { + callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); + return NULL; + } + + port_count = 1; + } + + /* Bind to ports */ + for (i = 0; i < port_count; i++) { + SILC_LOG_DEBUG(("Binding to local address %s:%d", + local_ip_addr ? local_ip_addr : "0.0.0.0", + ports ? ports[i] : 0)); + + l = new SilcSymbianTCPListener; + if (!l) + goto err; + + /* Connect to socket server */ + ret = l->ss.Connect(); + if (ret != KErrNone) + goto err; + +#ifdef SILC_THREADS + /* Make our socket shareable between threads */ + l->ss.ShareAuto(); +#endif /* SILC_THREADS */ + + /* Set listener address */ + if (!silc_net_set_sockaddr(&server, local_ip_addr, ports ? ports[i] : 0)) { + if (ignore_port_error) { + delete l; + continue; + } + goto err; } /* Create the socket */ ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp); if (ret != KErrNone) { - SILC_LOG_ERROR(("Cannot create socket")); + if (ignore_port_error) { + delete l; + continue; + } + SILC_LOG_ERROR(("Cannot create socket, error %d", ret)); goto err; } /* Set the socket options */ ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1); if (ret != KErrNone) { - SILC_LOG_ERROR(("Cannot set socket options")); + if (ignore_port_error) { + delete l; + continue; + } + SILC_LOG_ERROR(("Cannot set socket options, error %d", ret)); goto err; } /* Bind the listener socket */ ret = l->sock.Bind(server); if (ret != KErrNone) { - SILC_LOG_DEBUG(("Cannot bind socket")); + if (ignore_port_error) { + delete l; + continue; + } + SILC_LOG_DEBUG(("Cannot bind socket, error %d", ret)); goto err; } /* Specify that we are listenning */ ret = l->sock.Listen(5); if (ret != KErrNone) { - SILC_LOG_ERROR(("Cannot set socket listenning")); + if (ignore_port_error) { + delete l; + continue; + } + SILC_LOG_ERROR(("Cannot set socket listenning, error %d", ret)); goto err; } l->Listen(); @@ -219,6 +431,11 @@ silc_net_tcp_create_listener(const char **local_ip_addr, listener->socks_count++; } + if (ignore_port_error && !listener->socks_count) { + l = NULL; + goto err; + } + SILC_LOG_DEBUG(("TCP listener created")); return listener; @@ -227,7 +444,7 @@ silc_net_tcp_create_listener(const char **local_ip_addr, if (l) delete l; if (callback) - callback(SILC_NET_ERROR, NULL, context); + callback(SILC_ERR, NULL, context); if (listener) silc_net_close_listener(listener); return NULL; @@ -241,6 +458,9 @@ void silc_net_close_listener(SilcNetListener listener) SILC_LOG_DEBUG(("Closing network listener")); + if (!listener) + return; + for (i = 0; i < listener->socks_count; i++) { SilcSymbianTCPListener *l = (SilcSymbianTCPListener *)listener->socks[i]; l->sock.CancelAll(); @@ -255,11 +475,14 @@ void silc_net_close_listener(SilcNetListener listener) silc_free(listener); } + /**************************** TCP/IP connecting *****************************/ -static void silc_net_connect_stream(SilcSocketStreamStatus status, +static void silc_net_connect_stream(SilcResult status, SilcStream stream, void *context); +} /* extern "C" */ + /* TCP connecting class */ class SilcSymbianTCPConnect : public CActive { @@ -282,6 +505,7 @@ public: /* Connect to remote host */ void Connect(TSockAddr &addr) { + SILC_LOG_DEBUG(("Connect()")); sock->Connect(addr, iStatus); SetActive(); } @@ -289,9 +513,11 @@ public: /* Connection callback */ virtual void RunL() { + SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus)); + if (iStatus != KErrNone) { if (callback) - callback(SILC_NET_ERROR, NULL, context); + callback(SILC_ERR, NULL, context); sock->CancelConnect(); delete sock; ss->Close(); @@ -302,12 +528,16 @@ public: return; } + SILC_LOG_DEBUG(("Connected to host %s on %d", remote_ip, port)); + /* Create stream */ if (callback) { silc_socket_tcp_stream_create( (SilcSocket)silc_create_symbian_socket(sock, ss), TRUE, FALSE, schedule, silc_net_connect_stream, (void *)this); + sock = NULL; + ss = NULL; } else { sock->Close(); delete sock; @@ -315,9 +545,8 @@ public: delete ss; sock = NULL; ss = NULL; + delete this; } - - delete this; } /* Cancel */ @@ -344,27 +573,20 @@ public: void *context; }; -/* Stream creation callback */ +extern "C" { -static void silc_net_connect_stream(SilcSocketStreamStatus status, +/* TCP stream creation callback */ + +static void silc_net_connect_stream(SilcResult status, SilcStream stream, void *context) { SilcSymbianTCPConnect *conn = (SilcSymbianTCPConnect *)context; - SilcNetStatus net_status = SILC_NET_OK; - if (status != SILC_SOCKET_OK) { - /* In case of error, the socket has been destroyed already */ - if (status == SILC_SOCKET_UNKNOWN_IP) - net_status = SILC_NET_UNKNOWN_IP; - else if (status == SILC_SOCKET_UNKNOWN_HOST) - net_status = SILC_NET_UNKNOWN_HOST; - else - net_status = SILC_NET_ERROR; - } + SILC_LOG_DEBUG(("Socket stream creation status %d", status)); /* Call connection callback */ if (conn->callback) - conn->callback(net_status, stream, conn->context); + conn->callback(status, stream, conn->context); else if (stream) silc_stream_destroy(stream); @@ -381,7 +603,7 @@ static void silc_net_connect_abort(SilcAsyncOperation op, void *context) conn->callback = NULL; conn->op = NULL; if (conn->sock) - sock->CancelConnect(); + conn->sock->CancelConnect(); } /* Create TCP/IP connection */ @@ -395,19 +617,28 @@ SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr, { SilcSymbianTCPConnect *conn; TInetAddr local, remote; - SilcNetStatus status; - TBuf<64> tmp; + SilcResult status; TInt ret; - if (!remote_ip_addr || remote_port < 1 || !schedule || !callback) + if (!schedule) { + schedule = silc_schedule_get_global(); + if (!schedule) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + return NULL; + } + } + + if (!remote_ip_addr || remote_port < 1 || !callback) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return NULL; + } SILC_LOG_DEBUG(("Creating connection to host %s port %d", remote_ip_addr, remote_port)); conn = new SilcSymbianTCPConnect; if (!conn) { - callback(SILC_NET_NO_MEMORY, NULL, context); + callback(SILC_ERR_OUT_OF_MEMORY, NULL, context); return NULL; } conn->schedule = schedule; @@ -416,56 +647,58 @@ SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr, conn->port = remote_port; conn->remote = strdup(remote_ip_addr); if (!conn->remote) { - status = SILC_NET_NO_MEMORY; + status = SILC_ERR_OUT_OF_MEMORY; goto err; } /* Allocate socket */ conn->sock = new RSocket; if (!conn->sock) { - status = SILC_NET_NO_MEMORY; + status = SILC_ERR_OUT_OF_MEMORY; goto err; } /* Allocate socket server */ conn->ss = new RSocketServ; if (!conn->ss) { - status = SILC_NET_NO_MEMORY; + status = SILC_ERR_OUT_OF_MEMORY; goto err; } /* Connect to socket server */ ret = conn->ss->Connect(); if (ret != KErrNone) { - status = SILC_NET_ERROR; + SILC_LOG_ERROR(("Error connecting to socket server, error %d", ret)); + status = SILC_ERR; goto err; } +#ifdef SILC_THREADS + /* Make our socket shareable between threads */ + conn->ss->ShareAuto(); +#endif /* SILC_THREADS */ + /* Start async operation */ conn->op = silc_async_alloc(silc_net_connect_abort, NULL, (void *)conn); if (!conn->op) { - status = SILC_NET_NO_MEMORY; + status = SILC_ERR_OUT_OF_MEMORY; goto err; } /* Do host lookup */ - if (!silc_net_is_ip(remote_ip_addr)) { - if (!silc_net_gethostbyname(remote_ip_addr, FALSE, conn->remote_ip, - sizeof(conn->remote_ip))) { - SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " - "host", conn->remote)); - status = SILC_NET_HOST_UNREACHABLE; - goto err; - } - } else { - strcpy(conn->remote_ip, remote_ip_addr); + if (!silc_net_gethostbyname(remote_ip_addr, FALSE, conn->remote_ip, + sizeof(conn->remote_ip))) { + SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " + "host", conn->remote)); + status = SILC_ERR_UNREACHABLE; + goto err; } /* Create the connection socket */ ret = conn->sock->Open(*conn->ss, KAfInet, KSockStream, KProtocolInetTcp); if (ret != KErrNone) { - SILC_LOG_ERROR(("Cannot create socket")); - status = SILC_NET_ERROR; + SILC_LOG_ERROR(("Cannot create socket, error %d", ret)); + status = SILC_ERR; goto err; } @@ -474,21 +707,14 @@ SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr, conn->sock->SetOpt(KSoTcpKeepAlive, KSolInetTcp, 1); /* Bind to the local address if provided */ - if (local_ip_addr) { - local = TInetAddr(0); - tmp = (TText *)local_ip_addr; - ret = local.Input(tmp); - if (ret == KErrNone) - ret = conn->sock->Bind(local); - } + if (local_ip_addr) + if (silc_net_set_sockaddr(&local, local_ip_addr, 0)) + conn->sock->Bind(local); /* Connect to the host */ - remote = TInetAddr(remote_port); - tmp = (TText *)conn->remote_ip; - ret = remote.Input(tmp); - if (ret != KErrNone) { + if (!silc_net_set_sockaddr(&remote, conn->remote_ip, remote_port)) { SILC_LOG_ERROR(("Cannot connect (cannot set address)")); - status = SILC_NET_ERROR; + status = SILC_ERR; goto err; } conn->Connect(remote); @@ -527,13 +753,17 @@ SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port, TRequestStatus status; RSocket *sock = NULL; RSocketServ *ss = NULL; - TBuf<64> tmp; TInt ret; SILC_LOG_DEBUG(("Creating UDP stream")); - if (!schedule) - goto err; + if (!schedule) { + schedule = silc_schedule_get_global(); + if (!schedule) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + goto err; + } + } SILC_LOG_DEBUG(("Binding to local address %s", local_ip_addr ? local_ip_addr : "0.0.0.0")); @@ -551,16 +781,14 @@ SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port, if (ret != KErrNone) goto err; +#ifdef SILC_THREADS + /* Make our socket shareable between threads */ + ss->ShareAuto(); +#endif /* SILC_THREADS */ + /* Get local bind address */ - if (local_ip_addr) { - local = TInetAddr(local_port); - tmp = (TText *)local_ip_addr; - ret = local.Input(tmp); - if (ret != KErrNone) - goto err; - } else { - local = TInetAddr(KInetAddrAny, local_port); - } + if (!silc_net_set_sockaddr(&local, local_ip_addr, local_port)) + goto err; /* Create the socket */ ret = sock->Open(*ss, KAfInet, KSockDatagram, KProtocolInetUdp); @@ -581,16 +809,12 @@ SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port, /* Set to connected state if remote address is provided. */ if (remote_ip_addr && remote_port) { - remote = TInetAddr(remote_port); - tmp = (TText *)remote_ip_addr; - ret = remote.Input(tmp); - if (ret != KErrNone) - goto err; - - sock->Connect(remote, status); - if (status != KErrNone) { - SILC_LOG_DEBUG(("Cannot connect UDP stream")); - goto err; + if (silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port)) { + sock->Connect(remote, status); + if (status != KErrNone) { + SILC_LOG_DEBUG(("Cannot connect UDP stream")); + goto err; + } } } @@ -633,8 +857,8 @@ int silc_net_set_socket_nonblock(SilcSocket sock) SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len) { int ret = 0; - struct in_addr tmp; + ret = inet_aton(addr, &tmp); if (bin_len < 4) return FALSE; @@ -749,3 +973,5 @@ SilcUInt16 silc_net_get_local_port(SilcSocket sock) s->sock->LocalName(addr); return (SilcUInt16)addr.Port(); } + +} /* extern "C" */