Porting Toolkit to Symbian. It should work while some sporadic
[silc.git] / lib / silcutil / symbian / silcsymbiansocketstream.cpp
index fe9d57d64d38f570c3573643a4fc647904447ff8..cce36443ad519803c9f3bda1cfc8d68ec1275c04 100644 (file)
-\r
-/*\r
-\r
-  silcsymbiansocketstream.cpp\r
-\r
-  Author: Pekka Riikonen <priikone@silcnet.org>\r
-\r
-  Copyright (C) 2006 Pekka Riikonen\r
-\r
-  This program is free software; you can redistribute it and/or modify\r
-  it under the terms of the GNU General Public License as published by\r
-  the Free Software Foundation; version 2 of the License.\r
-\r
-  This program is distributed in the hope that it will be useful,\r
-  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  GNU General Public License for more details.\r
-\r
-*/\r
-\r
-/* In this implementation the sockets are in blocking mode, except that\r
-   on Symbian the blocking mode is actually asynchronous, which semantically\r
-   translates into non-blocking mode.  The non-blocking mode just is not\r
-   explicitly set because it would require us also to explicitly poll for the\r
-   socket, which is done automatically by the Active Scheduler in blocking\r
-   mode. */\r
-\r
-#include "silc.h"\r
-#include "silcsymbiansocketstream.h"\r
-\r
-/***************************** Socket Classes *******************************/\r
-\r
-/* Socket stream sender */\r
-\r
-class SilcSymbianSocketSend : public CActive {\r
-public:\r
-  /* Constructor */\r
-  SilcSymbianSocketSend() : CActive(CActive::EPriorityStandard)\r
-  {\r
-    CActiveScheduler::Add(this);\r
-  }\r
-\r
-  /* Destructor */\r
-  ~SilcSymbianSocketSend()\r
-  {\r
-    Cancel();\r
-  }\r
-\r
-  /* Send data */\r
-  void Send(const TDesC8& buf, TSockXfrLength& ret_len)\r
-  {\r
-    s->sock->Send(buf, 0, iStatus, ret_len);\r
-    SetActive();\r
-  }\r
-\r
-  /* Send data */\r
-  void Send(const TDesC8& buf, TSockXfrLength& ret_len,\r
-           const char *remote_ip, int remote_port)\r
-  {\r
-    TInetAddr remote;\r
-    TBuf<64> tmp;\r
-\r
-    remote = TInetAddr(remote_port);\r
-    tmp = (TText *)remote_ip;\r
-    if (remote.Input(tmp) == KErrNone) {\r
-      s->sock->SendTo(buf, remote, 0, iStatus, ret_len);\r
-      SetActive();\r
-    }\r
-  }\r
-\r
-  /* Sending callback */\r
-  void RunL()\r
-  {\r
-    if (iStatus != KErrNone) {\r
-      if (iStatus == KErrEof)\r
-       s->eof = 1;\r
-      else\r
-       s->error = 1;\r
-      return;\r
-    }\r
-\r
-    /* Call stream callback */\r
-    if (s->stream && s->stream->notifier)\r
-      s->stream->notifier(s->stream, SILC_STREAM_CAN_WRITE,\r
-                         s->stream->notifier_context);\r
-  }\r
-\r
-  /* Cancel */\r
-  void DoCancel()\r
-  {\r
-    s->sock->CancelWrite();\r
-  }\r
-\r
-  SilcSymbianSocket *s;\r
-};\r
-\r
-/* Socket stream receiver */\r
-\r
-class SilcSymbianSocketReceive : public CActive {\r
-public:\r
-  /* Constructor */\r
-  SilcSymbianSocketReceive() : CActive(CActive::EPriorityStandard)\r
-  {\r
-    CActiveScheduler::Add(this);\r
-  }\r
-\r
-  /* Destructor */\r
-  ~SilcSymbianSocketReceive()\r
-  {\r
-    Cancel();\r
-  }\r
-\r
-  /* Read data */\r
-  void Read()\r
-  {\r
-    if (!s->stream || s->stream->connected)\r
-      s->sock->RecvOneOrMore(inbuf, 0, iStatus, inbuf_len);\r
-    else\r
-      s->sock->RecvFrom(inbuf, remote, 0, iStatus);\r
-    SetActive();\r
-  }\r
-\r
-  /* Reading callback */\r
-  void RunL()\r
-  {\r
-    if (iStatus != KErrNone) {\r
-      if (iStatus == KErrEof)\r
-       s->eof = 1;\r
-      else\r
-       s->error = 1;\r
-      return;\r
-    }\r
-\r
-    if (!inbuf_ptr)\r
-      inbuf_ptr = inbuf.Ptr();\r
-    inbuf_len = inbuf.Length();\r
-\r
-    /* Call stream callback */\r
-    if (s->stream && s->stream->notifier)\r
-      s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,\r
-                         s->stream->notifier_context);\r
-\r
-    /* Read more */\r
-    Read();\r
-  }\r
-\r
-  /* Cancel */\r
-  void DoCancel()\r
-  {\r
-    s->sock->CancelRecv();\r
-  }\r
-\r
-  TBuf8<8192> inbuf;\r
-  const unsigned char *inbuf_ptr;\r
-  TSockXfrLength inbuf_len;\r
-  SilcSymbianSocket *s;\r
-  TInetAddr remote;\r
-};\r
-\r
-/* Creates symbian socket stream context */\r
-\r
-SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,\r
-                                             RSocketServ *ss)\r
-{\r
-  SilcSymbianSocket *stream;\r
-\r
-  stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));\r
-  if (!stream)\r
-    return NULL;\r
-  stream->sock = sock;\r
-  stream->ss = ss;\r
-\r
-  stream->send = new SilcSymbianSocketSend;\r
-  if (!stream->send) {\r
-    silc_free(stream);\r
-    return NULL;\r
-  }\r
-\r
-  stream->receive = new SilcSymbianSocketReceive;\r
-  if (!stream->receive) {\r
-    delete stream->send;\r
-    silc_free(stream);\r
-    return NULL;\r
-  }\r
-\r
-  return stream;\r
-}\r
-\r
-/***************************** SILC Stream API ******************************/\r
-\r
-/* Stream read operation */\r
-\r
-int silc_socket_stream_read(SilcStream stream, unsigned char *buf,\r
-                           SilcUInt32 buf_len)\r
-{\r
-  SilcSocketStream socket_stream = (SilcSocketStream)stream;\r
-  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;\r
-  SilcSymbianSocketReceive *recv = s->receive;\r
-  int len;\r
-\r
-  if (s->error || !s->stream)\r
-    return -2;\r
-  if (s->eof)\r
-    return 0;\r
-  if (!recv->inbuf_len() || !recv->inbuf_ptr)\r
-    return -1;\r
-\r
-  len = recv->inbuf_len();\r
-  if (buf_len < len)\r
-    len = buf_len;\r
-\r
-  /* Copy the read data */\r
-  memcpy(buf, recv->inbuf_ptr, len);\r
-\r
-  recv->inbuf_ptr = NULL;\r
-  if (len < recv->inbuf_len())\r
-    recv->inbuf_ptr += len;\r
-\r
-  return len;\r
-}\r
-\r
-/* Stream write operation */\r
-\r
-int silc_socket_stream_write(SilcStream stream, const unsigned char *data,\r
-                            SilcUInt32 data_len)\r
-{\r
-  SilcSocketStream socket_stream = (SilcSocketStream)stream;\r
-  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;\r
-  SilcSymbianSocketSend *send = s->send;\r
-  TSockXfrLength ret_len;\r
-  TPtrC8 write_buf(data, data_len);\r
-\r
-  if (s->would_block)\r
-    return -1;\r
-  if (s->error || !s->stream)\r
-    return -2;\r
-  if (s->eof)\r
-    return 0;\r
-\r
-  /* Send data */\r
-  send->Send(write_buf, ret_len);\r
-  if (send->iStatus.Int() != KErrNone) {\r
-    if (send->iStatus.Int() == KErrEof)\r
-      return 0;\r
-    return -2;\r
-  }\r
-\r
-  if (!ret_len())\r
-    return -1;\r
-\r
-  s->would_block = 0;\r
-  if (ret_len() < data_len)\r
-    s->would_block = 1;\r
-\r
-  return ret_len();\r
-}\r
-\r
-/* Receive UDP packet, connected socket. */\r
-\r
-int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,\r
-                               SilcUInt32 buf_len)\r
-{\r
-  return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);\r
-}\r
-\r
-/* Send UDP packet, connected socket. */\r
-\r
-int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,\r
-                                SilcUInt32 data_len)\r
-{\r
-  SilcSocketStream sock = (SilcSocketStream)stream;\r
-\r
-  /* In connectionless state check if remote IP and port is provided */\r
-  if (!sock->connected && sock->ip && sock->port)\r
-    return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);\r
-\r
-  /* In connected state use normal writing to socket. */\r
-  return silc_socket_stream_write(stream, data, data_len);\r
-}\r
-\r
-/* Receive UDP packet, connectionless socket */\r
-\r
-int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,\r
-                        SilcUInt32 remote_ip_addr_size, int *remote_port,\r
-                        unsigned char *buf, SilcUInt32 buf_len)\r
-{\r
-  SilcSocketStream socket_stream = (SilcSocketStream)stream;\r
-  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;\r
-  SilcSymbianSocketReceive *recv = s->receive;\r
-  int len;\r
-\r
-  if (s->eof)\r
-    return 0;\r
-  if (!recv->inbuf_len() || !recv->inbuf_ptr)\r
-    return -1;\r
-\r
-  len = recv->inbuf_len();\r
-  if (buf_len < len)\r
-    len = buf_len;\r
-\r
-  /* Copy the read data */\r
-  memcpy(buf, recv->inbuf_ptr, len);\r
-\r
-  recv->inbuf_ptr = NULL;\r
-  if (len < recv->inbuf_len())\r
-    recv->inbuf_ptr += len;\r
-\r
-  if (remote_ip_addr && remote_ip_addr_size && remote_port) {\r
-    TBuf<64> ip;\r
-    recv->remote.Output(ip);\r
-    silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),\r
-                ip.Length());\r
-    *remote_port = recv->remote.Port();\r
-  }\r
-\r
-  return len;\r
-}\r
-\r
-/* Send UDP packet, connectionless socket  */\r
-\r
-int silc_net_udp_send(SilcStream stream,\r
-                     const char *remote_ip_addr, int remote_port,\r
-                     const unsigned char *data, SilcUInt32 data_len)\r
-{\r
-  SilcSocketStream socket_stream = (SilcSocketStream)stream;\r
-  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;\r
-  SilcSymbianSocketSend *send = s->send;\r
-  TSockXfrLength ret_len;\r
-  TPtrC8 write_buf(data, data_len);\r
-\r
-  if (s->would_block)\r
-    return -1;\r
-  if (s->eof)\r
-    return 0;\r
-\r
-  /* Send data */\r
-  send->Send(write_buf, ret_len, remote_ip_addr, remote_port);\r
-  if (send->iStatus.Int() != KErrNone) {\r
-    if (send->iStatus.Int() == KErrEof)\r
-      return 0;\r
-    return -2;\r
-  }\r
-\r
-  if (!ret_len())\r
-    return -1;\r
-\r
-  s->would_block = 0;\r
-  if (ret_len() < data_len)\r
-    s->would_block = 1;\r
-\r
-  return ret_len();\r
-}\r
-\r
-/* Closes socket */\r
-\r
-SilcBool silc_socket_stream_close(SilcStream stream)\r
-{\r
-  SilcSocketStream socket_stream = (SilcSocketStream)stream;\r
-  SilcSymbianSocket *s;\r
-\r
-  if (!SILC_IS_SOCKET_STREAM(socket_stream) &&\r
-      !SILC_IS_SOCKET_STREAM_UDP(socket_stream))\r
-    return FALSE;\r
-\r
-  s = (SilcSymbianSocket *)socket_stream->sock;\r
-  s->sock->Close();\r
-\r
-  return TRUE;\r
-}\r
-\r
-/* Destroys the stream */\r
-\r
-void silc_socket_stream_destroy(SilcStream stream)\r
-{\r
-  SilcSocketStream socket_stream = (SilcSocketStream)stream;\r
-  SilcSymbianSocket *s;\r
-\r
-  if (!SILC_IS_SOCKET_STREAM(socket_stream) &&\r
-      !SILC_IS_SOCKET_STREAM_UDP(socket_stream))\r
-    return;\r
-\r
-  s = (SilcSymbianSocket *)socket_stream->sock;\r
-\r
-  silc_socket_stream_close(stream);\r
-  silc_free(socket_stream->ip);\r
-  silc_free(socket_stream->hostname);\r
-  silc_free(socket_stream);\r
-  delete s->send;\r
-  delete s->receive;\r
-  delete s->sock;\r
-  if (s->ss) {\r
-    s->ss->Close();\r
-    delete s->ss;\r
-  }\r
-  delete s;\r
-}\r
-\r
-/* Sets stream notification callback for the stream */\r
-\r
-void silc_socket_stream_notifier(SilcStream stream,\r
-                                SilcSchedule schedule,\r
-                                SilcStreamNotifier callback,\r
-                                void *context)\r
-{\r
-  SilcSocketStream socket_stream = (SilcSocketStream)stream;\r
-  SilcSymbianSocket *s;\r
-\r
-  if (!SILC_IS_SOCKET_STREAM(socket_stream) &&\r
-      !SILC_IS_SOCKET_STREAM_UDP(socket_stream))\r
-    return;\r
-\r
-  s = (SilcSymbianSocket *)socket_stream->sock;\r
-  if (callback)\r
-    s->stream = socket_stream;\r
-  else\r
-    s->stream = NULL;\r
-\r
-  socket_stream->notifier = callback;\r
-  socket_stream->notifier_context = context;\r
-  socket_stream->schedule = schedule;\r
-}\r
+
+/*
+
+  silcsymbiansocketstream.cpp
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2006 - 2007 Pekka Riikonen
+
+  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; version 2 of the License.
+
+  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.
+
+*/
+
+/* In this implementation the sockets are in blocking mode, except that
+   on Symbian the blocking mode is actually asynchronous, which semantically
+   translates into non-blocking mode.  The non-blocking mode just is not
+   explicitly set because it would require us also to explicitly poll for the
+   socket, which is done automatically by the Active Scheduler in blocking
+   mode. */
+
+#include "silc.h"
+#include "silcsymbiansocketstream.h"
+
+/***************************** Socket Classes *******************************/
+
+/* Socket stream sender */
+
+class SilcSymbianSocketSend : public CActive {
+public:
+  /* Constructor */
+  SilcSymbianSocketSend() : CActive(CActive::EPriorityStandard)
+  {
+    CActiveScheduler::Add(this);
+  }
+
+  /* Destructor */
+  ~SilcSymbianSocketSend()
+  {
+    Cancel();
+  }
+
+  /* Send data */
+  void Send(const TDesC8& buf, TSockXfrLength& ret_len)
+  {
+    SILC_LOG_DEBUG(("Send()"));
+    s->sock->Send(buf, 0, iStatus, ret_len);
+    if (!IsActive())
+      SetActive();
+  }
+
+  /* Send data */
+  void Send(const TDesC8& buf, TSockXfrLength& ret_len,
+           const char *remote_ip, int remote_port)
+  {
+    TInetAddr remote;
+    TBuf<64> tmp;
+
+    SILC_LOG_DEBUG(("Send()"));
+
+    remote = TInetAddr(remote_port);
+    tmp = (TText *)remote_ip;
+    if (remote.Input(tmp) == KErrNone) {
+      s->sock->SendTo(buf, remote, 0, iStatus, ret_len);
+      if (!IsActive())
+        SetActive();
+    }
+  }
+
+  /* Sending callback */
+  virtual void RunL()
+  {
+    SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
+
+    if (iStatus != KErrNone) {
+      if (iStatus == KErrEof)
+       s->eof = 1;
+      else
+       s->error = 1;
+      return;
+    }
+
+    /* Call stream callback */
+    if (s->would_block) {
+      s->would_block = 0;
+      if (s->stream && s->stream->notifier)
+       s->stream->notifier(s->stream, SILC_STREAM_CAN_WRITE,
+                           s->stream->notifier_context);
+    }
+  }
+
+  /* Cancel */
+  virtual void DoCancel()
+  {
+    s->sock->CancelWrite();
+  }
+
+  SilcSymbianSocket *s;
+};
+
+/* Socket stream receiver */
+
+class SilcSymbianSocketReceive : public CActive {
+public:
+  /* Constructor */
+  SilcSymbianSocketReceive() : CActive(CActive::EPriorityStandard)
+  {
+    CActiveScheduler::Add(this);
+  }
+
+  /* Destructor */
+  ~SilcSymbianSocketReceive()
+  {
+    Cancel();
+  }
+
+  /* Read data */
+  void Read()
+  {
+    SILC_LOG_DEBUG(("Read()"));
+
+    if (s->stream && s->stream->connected)
+      s->sock->RecvOneOrMore(inbuf, 0, iStatus, read_len);
+    else
+      s->sock->RecvFrom(inbuf, remote, 0, iStatus);
+
+    SetActive();
+  }
+
+  /* Reading callback */
+  virtual void RunL()
+  {
+    SILC_LOG_DEBUG(("RunL(), iStatus=%d", iStatus));
+
+    if (iStatus != KErrNone) {
+      if (iStatus == KErrEof)
+       s->eof = 1;
+      else
+       s->error = 1;
+
+      /* Call stream callback */
+      if (s->stream && s->stream->notifier)
+       s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
+                           s->stream->notifier_context);
+      return;
+    }
+
+    if (!s->stream || s->stream->connected)
+      inbuf_len = read_len();
+    else
+      inbuf_len = inbuf.Length();
+
+    if (inbuf_len) {
+      inbuf_ptr = inbuf.Ptr();
+      while (inbuf_ptr) {
+       /* Call stream callback until all has been read */
+       if (s->stream && s->stream->notifier)
+         s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
+                             s->stream->notifier_context);
+      }
+    }
+
+    /* Read more */
+    Read();
+  }
+
+  /* Cancel */
+  virtual void DoCancel()
+  {
+    s->sock->CancelRecv();
+  }
+
+  TBuf8<8192> inbuf;
+  const unsigned char *inbuf_ptr;
+  TInt inbuf_len;
+  TSockXfrLength read_len;
+  SilcSymbianSocket *s;
+  TInetAddr remote;
+};
+
+/* Creates symbian socket stream context */
+
+SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,
+                                             RSocketServ *ss)
+{
+  SilcSymbianSocket *stream;
+
+  stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));
+  if (!stream)
+    return NULL;
+  stream->sock = sock;
+  stream->ss = ss;
+
+  SILC_LOG_DEBUG(("Create new Symbian socket %p", stream));
+
+  stream->send = new SilcSymbianSocketSend;
+  if (!stream->send) {
+    silc_free(stream);
+    return NULL;
+  }
+  stream->send->s = stream;
+
+  stream->receive = new SilcSymbianSocketReceive;
+  if (!stream->receive) {
+    delete stream->send;
+    silc_free(stream);
+    return NULL;
+  }
+  stream->receive->s = stream;
+  stream->receive->inbuf_ptr = NULL;
+  stream->receive->inbuf_len = 0;
+
+  return stream;
+}
+
+/***************************** SILC Stream API ******************************/
+
+extern "C" {
+
+/* Stream read operation */
+
+int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
+                           SilcUInt32 buf_len)
+{
+  SilcSocketStream socket_stream = (SilcSocketStream)stream;
+  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
+  SilcSymbianSocketReceive *recv = s->receive;
+  int len;
+
+  SILC_LOG_DEBUG(("Reading from sock %p", s));
+
+  if (s->error || !s->stream) {
+    SILC_LOG_DEBUG(("Error reading from sock %p", s));
+    return -2;
+  }
+  if (s->eof) {
+    SILC_LOG_DEBUG(("EOF from sock %p", s));
+    return 0;
+  }
+  if (!recv->inbuf_len || !recv->inbuf_ptr) {
+    SILC_LOG_DEBUG(("Cannot read now from sock %p", s));
+    return -1;
+  }
+
+  len = recv->inbuf_len;
+  if (buf_len < len)
+    len = buf_len;
+
+  /* Copy the read data */
+  memcpy(buf, recv->inbuf_ptr, len);
+
+  if (len < recv->inbuf_len) {
+    recv->inbuf_ptr += len;
+    recv->inbuf_len -= len;
+  } else {
+    recv->inbuf_ptr = NULL;
+    recv->inbuf_len = 0;
+  }
+
+  SILC_LOG_DEBUG(("Read %d bytes", len));
+
+  return len;
+}
+
+/* Stream write operation */
+
+int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
+                            SilcUInt32 data_len)
+{
+  SilcSocketStream socket_stream = (SilcSocketStream)stream;
+  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
+  SilcSymbianSocketSend *send = s->send;
+  TSockXfrLength ret_len;
+  TPtrC8 write_buf(data, data_len);
+
+  SILC_LOG_DEBUG(("Writing to sock %p", s));
+
+  if (s->error || !s->stream) {
+    SILC_LOG_DEBUG(("Error writing to sock %p", s));
+    return -2;
+  }
+  if (s->eof) {
+    SILC_LOG_DEBUG(("EOF from sock %p", s));
+    return 0;
+  }
+  if (s->would_block) {
+    SILC_LOG_DEBUG(("Cannot write now to sock %p", s));
+    return -1;
+  }
+
+  /* Send data */
+  send->Send(write_buf, ret_len);
+  if (send->iStatus.Int() != KErrNone) {
+    if (send->iStatus.Int() == KErrEof) {
+      SILC_LOG_DEBUG(("EOF from sock %p", s));
+      return 0;
+    }
+    SILC_LOG_DEBUG(("Error writing to sock %p, error %d", s,
+                   send->iStatus.Int()));
+    return -2;
+  }
+
+  if (!ret_len())
+    return -1;
+
+  s->would_block = 0;
+  if (ret_len() < data_len)
+    s->would_block = 1;
+
+  SILC_LOG_DEBUG(("Wrote %d bytes", ret_len()));
+
+  return ret_len();
+}
+
+/* Receive UDP packet, connected socket. */
+
+int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
+                               SilcUInt32 buf_len)
+{
+  return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
+}
+
+/* Send UDP packet, connected socket. */
+
+int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
+                                SilcUInt32 data_len)
+{
+  SilcSocketStream sock = (SilcSocketStream)stream;
+
+  /* In connectionless state check if remote IP and port is provided */
+  if (!sock->connected && sock->ip && sock->port)
+    return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
+
+  /* In connected state use normal writing to socket. */
+  return silc_socket_stream_write(stream, data, data_len);
+}
+
+/* Receive UDP packet, connectionless socket */
+
+int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
+                        SilcUInt32 remote_ip_addr_size, int *remote_port,
+                        unsigned char *buf, SilcUInt32 buf_len)
+{
+  SilcSocketStream socket_stream = (SilcSocketStream)stream;
+  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
+  SilcSymbianSocketReceive *recv = s->receive;
+  int len;
+
+  if (s->eof)
+    return 0;
+  if (!recv->inbuf_len || !recv->inbuf_ptr)
+    return -1;
+
+  len = recv->inbuf_len;
+  if (buf_len < len)
+    len = buf_len;
+
+  /* Copy the read data */
+  memcpy(buf, recv->inbuf_ptr, len);
+
+  if (len < recv->inbuf_len) {
+    recv->inbuf_ptr += len;
+    recv->inbuf_len -= len;
+  } else {
+    recv->inbuf_ptr = NULL;
+    recv->inbuf_len = 0;
+  }
+
+  if (remote_ip_addr && remote_ip_addr_size && remote_port) {
+    TBuf<64> ip;
+    recv->remote.Output(ip);
+    silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),
+                ip.Length());
+    *remote_port = recv->remote.Port();
+  }
+
+  return len;
+}
+
+/* Send UDP packet, connectionless socket  */
+
+int silc_net_udp_send(SilcStream stream,
+                     const char *remote_ip_addr, int remote_port,
+                     const unsigned char *data, SilcUInt32 data_len)
+{
+  SilcSocketStream socket_stream = (SilcSocketStream)stream;
+  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
+  SilcSymbianSocketSend *send = s->send;
+  TSockXfrLength ret_len;
+  TPtrC8 write_buf(data, data_len);
+
+  if (s->would_block)
+    return -1;
+  if (s->eof)
+    return 0;
+
+  /* Send data */
+  send->Send(write_buf, ret_len, remote_ip_addr, remote_port);
+  if (send->iStatus.Int() != KErrNone) {
+    if (send->iStatus.Int() == KErrEof)
+      return 0;
+    return -2;
+  }
+
+  if (!ret_len())
+    return -1;
+
+  s->would_block = 0;
+  if (ret_len() < data_len)
+    s->would_block = 1;
+
+  return ret_len();
+}
+
+/* Closes socket */
+
+SilcBool silc_socket_stream_close(SilcStream stream)
+{
+  SilcSocketStream socket_stream = (SilcSocketStream)stream;
+  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
+  s->sock->Close();
+
+  return TRUE;
+}
+
+/* Destroys the stream */
+
+void silc_socket_stream_destroy(SilcStream stream)
+{
+  SilcSocketStream socket_stream = (SilcSocketStream)stream;
+  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
+
+  SILC_LOG_DEBUG(("Destroying sock %p", s));
+
+  silc_socket_stream_close(stream);
+  silc_free(socket_stream->ip);
+  silc_free(socket_stream->hostname);
+  silc_free(socket_stream);
+  delete s->send;
+  delete s->receive;
+  delete s->sock;
+  if (s->ss) {
+    s->ss->Close();
+    delete s->ss;
+  }
+  silc_free(s);
+}
+
+/* Sets stream notification callback for the stream */
+
+SilcBool silc_socket_stream_notifier(SilcStream stream,
+                                    SilcSchedule schedule,
+                                    SilcStreamNotifier callback,
+                                    void *context)
+{
+  SilcSocketStream socket_stream = (SilcSocketStream)stream;
+  SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
+
+  SILC_LOG_DEBUG(("Setting stream notifier for sock %p", s));
+
+  if (callback)
+    s->stream = socket_stream;
+  else
+    s->stream = NULL;
+
+  socket_stream->notifier = callback;
+  socket_stream->notifier_context = context;
+  socket_stream->schedule = schedule;
+
+  /* Schedule for receiving data by doing one read operation */
+  if (callback)
+    s->receive->Read();
+
+  return TRUE;
+}
+
+} /* extern "C" */