/src/pnpserver.cxx

http://github.com/foodmike/PTypes · C++ · 185 lines · 129 code · 44 blank · 12 comment · 20 complexity · b51459ac7b27f7b812285a0142c5a2f8 MD5 · raw file

  1. /*
  2. *
  3. * C++ Portable Types Library (PTypes)
  4. * Version 2.1.1 Released 27-Jun-2007
  5. *
  6. * Copyright (C) 2001-2007 Hovik Melikyan
  7. *
  8. * http://www.melikyan.com/ptypes/
  9. *
  10. */
  11. #ifdef WIN32
  12. # include <windows.h>
  13. #else
  14. # include <sys/time.h>
  15. # include <sys/types.h>
  16. # include <sys/socket.h>
  17. # include <sys/un.h>
  18. # include <unistd.h>
  19. #endif
  20. #include "pstreams.h"
  21. PTYPES_BEGIN
  22. npserver::npserver(const string& ipipename)
  23. : pipename(), handle(invhandle), active(false)
  24. {
  25. pipename = namedpipe::realpipename(ipipename);
  26. }
  27. npserver::~npserver()
  28. {
  29. close();
  30. }
  31. void npserver::error(int code, const char* defmsg)
  32. {
  33. string msg = unixerrmsg(code);
  34. if (isempty(msg))
  35. msg = defmsg;
  36. msg += " [" + pipename + ']';
  37. throw new estream(nil, code, msg);
  38. }
  39. #ifdef WIN32
  40. void npserver::openinst()
  41. {
  42. // called once at startup and then again, after
  43. // each client connection. strange logic, to say the least...
  44. SECURITY_ATTRIBUTES sa;
  45. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  46. sa.lpSecurityDescriptor = NULL;
  47. sa.bInheritHandle = TRUE;
  48. handle = (int)CreateNamedPipe(pipename,
  49. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  50. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
  51. PIPE_UNLIMITED_INSTANCES,
  52. DEF_PIPE_SYSTEM_BUF_SIZE, DEF_PIPE_SYSTEM_BUF_SIZE,
  53. DEF_PIPE_TIMEOUT, &sa);
  54. if (handle == invhandle)
  55. error(unixerrno(), "Couldn't create");
  56. }
  57. void npserver::closeinst()
  58. {
  59. CloseHandle(HANDLE(pexchange(&handle, invhandle)));
  60. }
  61. #endif
  62. void npserver::open()
  63. {
  64. close();
  65. #ifdef WIN32
  66. openinst();
  67. #else
  68. sockaddr_un sa;
  69. if (!namedpipe::setupsockaddr(pipename, &sa))
  70. error(ERANGE, "Socket name too long");
  71. if ((handle = ::socket(sa.sun_family, SOCK_STREAM, 0)) < 0)
  72. error(unixerrno(), "Couldn't create local socket");
  73. unlink(pipename);
  74. if (::bind(handle, (sockaddr*)&sa, sizeof(sa)) != 0)
  75. error(unixerrno(), "Couldn't bind local socket");
  76. if (::listen(handle, SOMAXCONN) != 0)
  77. error(unixerrno(), "Couldn't listen on local socket");
  78. #endif
  79. active = true;
  80. }
  81. void npserver::close()
  82. {
  83. if (active)
  84. {
  85. active = false;
  86. #ifdef WIN32
  87. closeinst();
  88. #else
  89. ::close(pexchange(&handle, invhandle));
  90. unlink(pipename);
  91. #endif
  92. }
  93. }
  94. bool npserver::serve(namedpipe& client, int timeout)
  95. {
  96. if (!active)
  97. open();
  98. client.cancel();
  99. #ifdef WIN32
  100. client.ovr.Offset = 0;
  101. client.ovr.OffsetHigh = 0;
  102. bool result = ConnectNamedPipe(HANDLE(handle), &client.ovr) ?
  103. true : (GetLastError() == ERROR_PIPE_CONNECTED);
  104. if (!result && GetLastError() == ERROR_IO_PENDING)
  105. {
  106. if (WaitForSingleObject(client.ovr.hEvent, timeout) == WAIT_TIMEOUT)
  107. return false;
  108. unsigned long ret;
  109. if (!GetOverlappedResult(HANDLE(handle), &client.ovr, &ret, false))
  110. error(unixerrno(), "Couldn't read");
  111. result = true;
  112. }
  113. if (result)
  114. {
  115. client.svhandle = handle;
  116. client.pipename = pipename;
  117. openinst();
  118. client.open();
  119. return true;
  120. }
  121. else
  122. error(unixerrno(), "Couldn't connect to client");
  123. return false;
  124. #else
  125. fd_set set;
  126. FD_ZERO(&set);
  127. FD_SET((uint)handle, &set);
  128. timeval t;
  129. t.tv_sec = timeout / 1000;
  130. t.tv_usec = (timeout % 1000) * 1000;
  131. if (::select(FD_SETSIZE, &set, nil, nil, (timeout < 0) ? nil : &t) > 0)
  132. {
  133. client.svhandle = handle;
  134. client.pipename = pipename;
  135. client.open();
  136. return true;
  137. }
  138. return false;
  139. #endif
  140. }
  141. PTYPES_END