libzypp 17.37.10

socket.cc
Go to the documentation of this file.
1#include "private/socket_p.h"
2#include <errno.h>
3#include <string.h>
4#include <zypp-core/base/Logger.h>
5#include <zypp-core/AutoDispose.h>
6#include <zypp-core/zyppng/base/EventDispatcher>
7#include <zypp-core/zyppng/base/private/linuxhelpers_p.h>
8#include <sys/ioctl.h> //For FIONREAD
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <fcntl.h>
12
13#include <iostream>
14
15 namespace zyppng {
16
17 SocketPrivate::ClosingState::ClosingState(IOBuffer &&writeBuffer)
18 : _writeBuffer( std::move(writeBuffer) )
19 { }
20
21 bool SocketPrivate::initSocket()
22 {
23 if ( _socket >= 0 )
24 return true;
25
26 _error = Socket::NoError;
27 _emittedErr = false;
28
29 // Since Linux 2.6.27 we can pass additional flags with the type argument to avoid fcntl
30 // if creating sockets fails we might need to change that
31 _socket = eintrSafeCall( ::socket, _domain, _type | SOCK_NONBLOCK | SOCK_CLOEXEC, _protocol );
32 if ( _socket >= 0 )
33 return true;
34
35 switch ( errno ) {
36 case EACCES:
37 setError( Socket::InsufficientPermissions, strerr_cxx() );
38 break;
39 case EINVAL:
40 setError( Socket::InvalidSocketOptions, strerr_cxx() );
41 break;
42 case EMFILE:
43 case ENFILE:
44 case ENOBUFS:
45 case ENOMEM:
46 setError( Socket::InsufficientRessources, strerr_cxx() );
47 break;
48 case EAFNOSUPPORT:
49 case EPROTONOSUPPORT:
50 setError ( Socket::UnsupportedSocketOptions, strerr_cxx() );
51 break;
52 default:
53 setError( Socket::UnknownSocketError, strerr_cxx() );
54 break;
55 }
56
57 return false;
58 }
59
60 void SocketPrivate::setError( Socket::SocketError error , std::string &&err, bool emit )
61 {
62 // we only remember the first error that happend
63 if ( _error == Socket::NoError && _error != error ) {
64 _emittedErr = emit;
65 _error = error;
66 _errorDesc = std::move(err);
67 }
68 if ( emit && !_emittedErr )
69 _sigError.emit( error );
70 }
71
72 bool SocketPrivate::transition( Socket::SocketState newState )
73 {
74 const auto oldState = state();
75
76 if ( oldState == newState )
77 return true;
78
79 switch ( newState ) {
80 case Socket::InitialState:
81 setError( Socket::InternalError, "Invalid state transition" );
82 return false;
83 case Socket::ConnectingState:
84 if ( oldState != Socket::InitialState && oldState != Socket::ClosedState ) {
85 setError( Socket::InternalError, "Invalid state transition" );
86 return false;
87 }
88 _state.emplace<SocketPrivate::ConnectingState>( );
89 return connectToHost();
90 break;
91 case Socket::ConnectedState: {
92 if ( oldState != Socket::InitialState && oldState != Socket::ConnectingState ) {
93 setError( Socket::InternalError, "Invalid state transition" );
94 return false;
95 }
96 auto &s = _state.emplace<SocketPrivate::ConnectedState>();
97 s._socketNotifier = SocketNotifier::create( _socket, SocketNotifier::Read | SocketNotifier::Error, true );
98 s._socketNotifier->connect( &SocketNotifier::sigActivated, *this, &SocketPrivate::onSocketActivatedSlot );
99
100 z_func()->IODevice::open( IODevice::ReadOnly | IODevice::WriteOnly );
101
102 _connected.emit();
103 break;
104 }
105 case Socket::ListeningState: {
106 if ( state() != Socket::InitialState ) {
107 setError( Socket::InternalError, "Invalid state transition" );
108 return false;
109 }
110 auto &s = _state.emplace<SocketPrivate::ListeningState>();
111 s._socketNotifier = SocketNotifier::create( _socket, SocketNotifier::Read, true );
112 s._socketNotifier->connect( &SocketNotifier::sigActivated, *this, &SocketPrivate::onSocketActivatedSlot );
113 break;
114 }
115 case Socket::ClosingState: {
116 if ( state() != Socket::ConnectedState ) {
117 setError( Socket::InternalError, "Invalid state transition" );
118 return false;
119 }
120
121 auto wbOld = std::move( std::get<ConnectedState>(_state)._writeBuffer );
122 auto &s = _state.emplace<SocketPrivate::ClosingState>( std::move( wbOld ) );
123 s._socketNotifier = SocketNotifier::create( _socket, SocketNotifier::Write, true );
124 s._socketNotifier->connect( &SocketNotifier::sigActivated, *this, &SocketPrivate::onSocketActivatedSlot );
125 break;
126 }
127 case Socket::ClosedState: {
128 _state.emplace<SocketPrivate::ClosedState>();
129 if ( z_func()->canRead() )
130 z_func()->finishReadChannel( 0 );
131 if ( _socket >= 0 && !_borrowedSocket )
132 ::close( _socket );
133 _socket = -1;
134 _targetAddr.reset();
135 _disconnected.emit();
136 z_func()->IODevice::close();
137 break;
138 }
139 }
140 return true;
141 }
142
143 bool SocketPrivate::connectToHost()
144 {
145 auto &state = std::get<ConnectingState>( _state );
146
147 const int res = eintrSafeCall( ::connect, _socket, _targetAddr->nativeSockAddr(), _targetAddr->size() );
148
149 auto doDelayedConnect = [ this, &state ](){
150 if ( !state._connectNotifier ) {
151 state._connectNotifier = SocketNotifier::create( _socket, SocketNotifier::Write, true );
152 state._connectNotifier->connect( &SocketNotifier::sigActivated, *this, &SocketPrivate::onSocketActivatedSlot );
153 }
154
155 if ( !state._connectTimeout ) {
156 state._connectTimeout = Timer::create();
157 state._connectTimeout->connectFunc( &Timer::sigExpired, [this, &state ]( const auto &) {
158 setError( Socket::ConnectionTimeout, "The connection timed out." );
159 state._connectNotifier.reset();
160 state._connectTimeout.reset();
161 }, *z_func());
162 }
163 state._connectTimeout->setSingleShot( true );
164 state._connectTimeout->start( 30000 );
165 setError( Socket::ConnectionDelayed, "" );
166 return false;
167 };
168
169 if ( res < 0 ) {
170 switch ( errno ) {
171 case EAGAIN: {
172 if ( _targetAddr->nativeSockAddr()->sa_family == AF_UNIX ) {
173 // the Servers backlog is full , we need to wait
174 return doDelayedConnect();
175 } else {
176 setError( Socket::FailedSocketOperation, strerr_cxx() );
177 z_func()->close();
178 return false;
179 }
180 break;
181 }
182 case EINPROGRESS:
183 return doDelayedConnect();
184 break;
185
186 default:
187 if ( handleConnectError( errno ) == false ) {
188 z_func()->close();
189 return false;
190 }
191 }
192 }
193
194 // connected yay
195 if ( !transition( Socket::ConnectedState ) ) {
196 z_func()->close();
197 return false;
198 }
199 return true;
200 }
201
202 int64_t zyppng::SocketPrivate::rawBytesAvailable() const
203 {
204 if ( state() != Socket::ConnectedState )
205 return 0;
206
207 return zyppng::bytesAvailableOnFD( _socket );
208 }
209
210 bool SocketPrivate::readRawBytesToBuffer()
211 {
212 Z_Z();
213 auto bytesToRead = rawBytesAvailable();
214 if ( bytesToRead == 0 ) {
215 // make sure to check if bytes are available even if the ioctl call returns something different
216 bytesToRead = 4096;
217 }
218
219 auto &readBuf = _readChannels[0];
220 char *buf = readBuf.reserve( bytesToRead );
221 const auto bytesRead = z_func()->readData( 0, buf, bytesToRead );
222
223 if ( bytesRead <= 0 ) {
224 readBuf.chop( bytesToRead );
225
226 switch ( bytesRead ) {
227 case -2:
228 // there is simply no data to read ignore and try again
229 return true;
230 case 0: {
231 // remote close
232 setError( Socket::ConnectionClosedByRemote, "The remote host closed the connection", true );
233 break;
234 }
235 case -1:
236 default: {
237 setError( Socket::InternalError, strerr_cxx(), true );
238 break;
239 }
240 }
241 z->abort();
242 return false;
243 }
244
245 if ( bytesToRead > bytesRead )
246 readBuf.chop( bytesToRead-bytesRead );
247
248 _readyRead.emit();
249 _channelReadyRead.emit(0);
250 return true;
251 }
252
253 bool SocketPrivate::writePendingData()
254 {
255 return std::visit( [this]( auto &s ){
256 using T = std::decay_t<decltype (s)>;
257 if constexpr ( std::is_same_v<T, ConnectedState> || std::is_same_v<T, ClosingState> ) {
258 const auto nwrite = s._writeBuffer.frontSize();
259 if ( !nwrite ) {
260 // disable Write notifications so we do not wake up without the need to
261 s._socketNotifier->setMode( SocketNotifier::Read | SocketNotifier::Error );
262 return true;
263 }
264
265 const auto nBuf = s._writeBuffer.front();
266 const auto written = eintrSafeCall( ::send, _socket, nBuf, nwrite, MSG_NOSIGNAL );
267 if ( written == -1 ) {
268 switch ( errno ) {
269 case EACCES:
270 setError( Socket::InsufficientPermissions, strerr_cxx() );
271 return false;
272 case EAGAIN:
273#if EAGAIN != EWOULDBLOCK
274 case EWOULDBLOCK:
275#endif
276 return true;
277 case EPIPE:
278 case ECONNRESET:
279 setError( Socket::ConnectionClosedByRemote, strerr_cxx() );
280 return false;
281 default:
282 setError( Socket::InternalError, strerr_cxx() );
283 return false;
284 }
285 return false;
286 }
287 s._writeBuffer.discard( written );
288 _sigBytesWritten.emit( written );
289 if ( s._writeBuffer.size() == 0 )
290 _sigAllBytesWritten.emit();
291 }
292 return true;
293 }, _state );
294 }
295
300 bool zyppng::SocketPrivate::handleConnectError( int error )
301 {
302 switch ( error ) {
303 case EACCES:
304 case EPERM:
305 setError( Socket::InsufficientPermissions, strerr_cxx() );
306 return false;
307 case EADDRINUSE:
308 setError( Socket::AddressInUse, strerr_cxx() );
309 return false;
310 case EADDRNOTAVAIL:
311 setError( Socket::AddressNotAvailable, strerr_cxx() );
312 return false;
313 case EAFNOSUPPORT:
314 setError( Socket::AddressIssue, strerr_cxx() );
315 return false;
316 case ETIMEDOUT:
317 setError( Socket::ConnectionTimeout, strerr_cxx() );
318 return false;
319 case EALREADY:
320 setError( Socket::ConnectionDelayed, "" );
321 return false;
322 case ECONNREFUSED:
323 setError( Socket::ConnectionRefused, strerr_cxx() );
324 return false;
325 case EBADF:
326 case EFAULT:
327 case ENOTSOCK:
328 setError( Socket::InternalError, strerr_cxx() ); // this can only happen if we screw up
329 return false;
330 case ENETUNREACH:
331 setError( Socket::NetworkUnreachable, strerr_cxx() );
332 return false;
333 case EPROTOTYPE:
334 setError ( Socket::InvalidSocketOptions, strerr_cxx() );
335 return false;
336 case EISCONN:
337 break;
338 }
339 return true;
340 }
341
342
343 void SocketPrivate::onSocketActivated( int ev )
344 {
345 std::visit( [ this, &ev ] ( const auto &currState ) {
346 using T = std::decay_t<decltype(currState)>;
347 if constexpr ( std::is_same<ConnectingState, T>() ) {
348 if ( (ev & SocketNotifier::Write) == SocketNotifier::Write ) {
349 if ( this->_targetAddr->nativeSockAddr()->sa_family == AF_UNIX ) {
350 // for AF_UNIX sockets we just call connect again
351 this->connectToHost();
352 return;
353 } else {
354
355 // for others we check with getsockopt as mentioned in connect(2) if the conn was successful
356 int err = 0;
357 socklen_t errSize = sizeof ( err );
358 ::getsockopt( _socket, SOL_SOCKET, SO_ERROR, &err, &errSize );
359
360 if ( err == 0 || err == EISCONN ) {
361 transition( Socket::ConnectedState );
362 } else {
363 if ( err == EINPROGRESS || err == EAGAIN || err == EALREADY )
364 return;
365 handleConnectError( err );
366 z_func()->abort();
367 }
368 }
369 }
370
371 } else if constexpr ( std::is_same<ConnectedState, T>() ) {
372 if ( (ev & SocketNotifier::Write) == SocketNotifier::Write ) {
373 if ( !writePendingData() ) {
374 z_func()->abort();
375 return;
376 }
377 }
378 if ( (ev & SocketNotifier::Read) == SocketNotifier::Read ) {
379 if ( !readRawBytesToBuffer() ) {
380 z_func()->abort();
381 return;
382 }
383 }
384 if ( (ev & SocketNotifier::Error) == SocketNotifier::Error ) {
385 return;
386 }
387
388 } else if constexpr ( std::is_same<ClosingState, T>() ) {
389
390 if ( (ev & SocketNotifier::Write) == SocketNotifier::Write ) {
391 if ( !writePendingData() ) {
392 z_func()->abort();
393 return;
394
395 }
396
397 if ( currState._writeBuffer.size() == 0 ) {
398 transition( Socket::ClosedState );
399 }
400 }
401
402 } else if constexpr ( std::is_same<ListeningState, T>() ) {
403
404 //signal that we have pending connections
405 _incomingConnection.emit();
406
407 } else {
408 DBG << "Unexpected state on socket activation" << std::endl;
409 }
410 },_state);
411 }
412
413 Socket::SocketState SocketPrivate::state() const
414 {
415 return std::visit([]( const auto &s ) constexpr { return s.type(); }, _state );
416 }
417
418 Socket::Ptr SocketPrivate::wrapSocket(int fd, int domain, int type, int protocol, Socket::SocketState state)
419 {
420 // from here on the Socket instance owns the fd, no need to manually close it
421 // in case of error
422 auto sptr = Socket::create( domain, type, protocol );
423 sptr->d_func()->_socket = fd;
424
425 // make sure the socket is non blocking
426 if ( !sptr->setBlocking( false ) ) {
427 DBG << "Failed to unblock socket." << std::endl;
428 return nullptr;
429 }
430
431 if( sptr->d_func()->transition( state ) )
432 return sptr;
433
434 return nullptr;
435 }
436
437 ZYPP_IMPL_PRIVATE(Socket)
438
439 Socket::Socket( int domain, int type, int protocol )
440 : IODevice( *( new SocketPrivate( domain, type, protocol, *this )))
441 { }
442
443 int64_t Socket::rawBytesAvailable( uint channel ) const
444 {
445 if ( channel != 0 ) {
446 constexpr std::string_view msg("Socket does not support multiple read channels");
447 ERR << msg << std::endl;
448 throw std::logic_error( msg.data() );
449 }
450 return d_func()->rawBytesAvailable();
451 }
452
453 Socket::~Socket()
454 {
455 this->abort();
456 }
457
458 Socket::Ptr Socket::create( int domain, int type, int protocol )
459 {
460 return Ptr( new Socket( domain, type, protocol ) );
461 }
462
463 bool Socket::bind( const std::shared_ptr<SockAddr> &addr )
464 {
465 Z_D();
466 if ( !addr || !d->initSocket() )
467 return false;
468
469 int res = eintrSafeCall( ::bind, d->_socket, addr->nativeSockAddr(), addr->size() );
470 if ( res >= 0) return true;
471
472 switch ( errno ) {
473 case EACCES:
474 d->setError( Socket::InsufficientPermissions, strerr_cxx() );
475 break;
476 case EADDRINUSE:
477 d->setError( Socket::AddressInUse, strerr_cxx() );
478 break;
479 case EBADF:
480 case ENOTSOCK:
481 case EFAULT:
482 d->setError( Socket::InternalError, strerr_cxx() ); // this can only happen if we screw up
483 break;
484 case EINVAL:
485 d->setError( Socket::SocketAlreadyBound, strerr_cxx() );
486 break;
487 case EADDRNOTAVAIL:
488 d->setError( Socket::AddressNotAvailable, strerr_cxx() );
489 break;
490 case ELOOP:
491 case ENAMETOOLONG:
492 case ENOENT:
493 case ENOTDIR:
494 case EROFS:
495 d->setError( Socket::AddressIssue, strerr_cxx() );
496 break;
497 case ENOMEM:
498 d->setError( Socket::InsufficientRessources, strerr_cxx() );
499 break;
500 default:
501 d->setError( Socket::UnknownSocketError, strerr_cxx() );
502 break;
503 }
504
505 abort();
506 return false;
507 }
508
509 bool Socket::listen(int backlog)
510 {
511 Z_D();
512 if ( !d->initSocket() )
513 return false;
514
515 int res = eintrSafeCall( ::listen, d->_socket, backlog );
516 if ( res >= 0 ) {
517 d->transition( Socket::ListeningState );
518 return true;
519 }
520
521 switch ( errno ) {
522
523 case EADDRINUSE:
524 d->setError( Socket::AddressInUse, strerr_cxx() );
525 break;
526 case EBADF:
527 case ENOTSOCK:
528 d->setError( Socket::InternalError, strerr_cxx() ); // this can only happen if we screw up
529 break;
530 case EOPNOTSUPP:
531 d->setError( Socket::OperationNotSupported, strerr_cxx() );
532 break;
533
534 }
535 return false;
536 }
537
538 Socket::Ptr Socket::accept()
539 {
540 Z_D();
541 if ( d->_socket == -1 )
542 return nullptr;
543
544 //accept new pending connections
545 const auto res = eintrSafeCall( ::accept4, d->_socket, (struct sockaddr*)nullptr, (socklen_t *)nullptr, SOCK_CLOEXEC );
546 if ( res < 0 ) {
547 switch ( errno ) {
548#if EAGAIN != EWOULDBLOCK
549 case EWOULDBLOCK:
550#endif
551 case EAGAIN:
552 case ECONNABORTED:
553 return nullptr;
554 break;
555 default:
556 d->setError( Socket::InternalError, strerr_cxx() );
557 return nullptr;
558 }
559 }
560
561 return SocketPrivate::wrapSocket( res, d->_domain, d->_type, d->_protocol, Socket::ConnectedState );
562 }
563
564 Socket::Ptr Socket::fromSocket( int fd, Socket::SocketState state )
565 {
566
567 int domain = 0;
568 socklen_t optlen = sizeof(domain);
569 int res = getsockopt( fd, SOL_SOCKET, SO_DOMAIN, &domain, &optlen );
570 if ( res < 0 ) {
571 DBG << "Error querying socket domain: " << strerr_cxx() << std::endl;
572 ::close(fd);
573 return nullptr;
574 }
575
576 int protocol = 0;
577 optlen = sizeof(protocol);
578 res = getsockopt( fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &optlen );
579 if ( res < 0 ) {
580 DBG << "Error querying socket protocol: " << strerr_cxx() << std::endl;
581 ::close(fd);
582 return nullptr;
583 }
584
585 int type = 0;
586 optlen = sizeof(type);
587 res = getsockopt( fd, SOL_SOCKET, SO_TYPE, &type, &optlen );
588 if ( res < 0 ) {
589 DBG << "Error querying socket type: " << strerr_cxx() << std::endl;
590 ::close(fd);
591 return nullptr;
592 }
593
594 return SocketPrivate::wrapSocket( fd, domain, type, protocol, state );
595 }
596
597 bool Socket::setBlocking( const bool set )
598 {
599 Z_D();
600
601 if ( !d->initSocket() )
602 return false;
603
604 const int oldFlags = fcntl( d->_socket, F_GETFL, 0 );
605 if (oldFlags == -1) return false;
606
607 const int flags = set ? ( oldFlags & ~(O_NONBLOCK) ) : ( oldFlags | O_NONBLOCK );
608
609 // no need to do a syscall if we do not change anything
610 if ( flags == oldFlags )
611 return true;
612
613 if ( fcntl( d->_socket, F_SETFL, flags ) != 0) {
614 return false;
615 }
616 return true;
617 }
618
619 bool Socket::connect( std::shared_ptr<SockAddr> addr )
620 {
621 Z_D();
622
623 if ( !addr || ( d->state() != Socket::InitialState && d->state() != Socket::ClosedState ) )
624 return false;
625
626 if ( !d->initSocket() )
627 return false;
628
629 d->_targetAddr = std::move(addr);
630 if ( !d->transition( Socket::ConnectingState ) ) {
631 abort();
632 return false;
633 }
634
635 return d->state() == Socket::ConnectedState;
636 }
637
638 int Socket::nativeSocket() const
639 {
640 Z_D();
641 return d->_socket;
642 }
643
644 int Socket::releaseSocket()
645 {
646 Z_D();
647 auto sock = d->_socket;
648 d->_socket = -1;
649 d->transition( Socket::ClosedState );
650 return sock;
651 }
652
653 Socket::SocketError Socket::lastError() const
654 {
655 Z_D();
656 return d->_error;
657 }
658
659 void Socket::abort()
660 {
661 Z_D();
662 d->transition( ClosedState );
663 }
664
665 void Socket::close()
666 {
667 disconnect();
668 }
669
670 void Socket::disconnect()
671 {
672 Z_D();
673 std::visit([&d]( const auto &s ){
674 using Type = std::decay_t<decltype (s)>;
675 if constexpr ( std::is_same_v<Type, SocketPrivate::ConnectedState > ) {
676 // we still have pending data, we need to wait for it to be written
677 if ( s._writeBuffer.size() ) {
678 d->transition( Socket::ClosingState );
679 return;
680 }
681 }
682 d->transition( Socket::ClosedState );
683 }, d->_state );
684
685 }
686
687 int64_t Socket::writeData( const char *data, int64_t count )
688 {
689 Z_D();
690 if ( d->state() != SocketState::ConnectedState )
691 return 0;
692
693 auto &s = std::get<SocketPrivate::ConnectedState>( d->_state );
694
695 // if the write buffer has already data we need to append to it to keep the correct order
696 if ( s._writeBuffer.size() ) {
697 s._writeBuffer.append( data, count );
698 //lets try to write some of it
699 d->writePendingData();
700 return count;
701 }
702
703 auto written = eintrSafeCall( ::send, d->_socket, data, count, MSG_NOSIGNAL );
704 if ( written == -1 ) {
705 switch ( errno ) {
706#if EAGAIN != EWOULDBLOCK
707 case EWOULDBLOCK:
708#endif
709 case EAGAIN: {
710 written = 0;
711 break;
712 }
713 case EPIPE:
714 case ECONNRESET: {
715 d->setError( Socket::ConnectionClosedByRemote, strerr_cxx( errno ) );
716 return -1;
717 }
718 default: {
719 d->setError( Socket::UnknownSocketError, strerr_cxx( errno ) );
720 return -1;
721 }
722 }
723 }
724
725 if ( written >= 0 ) {
726 if ( written < count ) {
727 // append the rest of the data to the buffer, so we can return always the full count
728 s._writeBuffer.append( data + written, count - written );
729 s._socketNotifier->setMode( SocketNotifier::Read | SocketNotifier::Write | SocketNotifier::Error );
730 }
731 if ( written > 0 )
732 d->_sigBytesWritten.emit( written );
733 }
734
735 if ( s._writeBuffer.size() == 0 )
736 d->_sigAllBytesWritten.emit();
737
738 return count;
739 }
740
741 bool Socket::waitForConnected( int timeout )
742 {
743 Z_D();
744 if ( d->state() == Socket::ConnectedState )
745 return true;
746 // we can only wait if we are in connecting state
747 while ( d->state() == Socket::ConnectingState ) {
748 int rEvents = 0;
749 if ( EventDispatcher::waitForFdEvent( d->_socket, AbstractEventSource::Write, rEvents, timeout ) ) {
750 d->onSocketActivated( rEvents );
751 } else {
752 // timeout
753 return false;
754 }
755 }
756 return d->state() == Socket::ConnectedState;
757 }
758
759 bool Socket::waitForAllBytesWritten( int timeout )
760 {
761 Z_D();
762
763 bool canContinue = true;
764 bool bufferEmpty = false;
765
766 while ( canContinue && !bufferEmpty ) {
767
768 if ( d->state() != Socket::ConnectedState && d->state() != Socket::ClosingState)
769 return false;
770
771 std::visit([&]( const auto &s ){
772 using T = std::decay_t<decltype (s)>;
773 if constexpr ( std::is_same_v<T, SocketPrivate::ConnectedState> || std::is_same_v<T, SocketPrivate::ClosingState> ) {
774 if ( s._writeBuffer.size() > 0 ) {
775 int rEvents = 0;
776 canContinue = EventDispatcher::waitForFdEvent( d->_socket, AbstractEventSource::Write | AbstractEventSource::Read, rEvents, timeout );
777 if ( canContinue ) {
778 //this will trigger the bytesWritten signal, we check there if the buffer is empty
779 d->onSocketActivated( rEvents );
780 }
781 }
782 if ( s._writeBuffer.size() == 0 ){
783 canContinue = false;
784 bufferEmpty = true;
785 }
786 }
787 }, d->_state );
788 }
789 return bufferEmpty;
790 }
791
792 bool Socket::waitForReadyRead( uint channel, int timeout)
793 {
794 Z_D();
795 if ( d->state() != Socket::ConnectedState || channel != 0 )
796 return false;
797
798 // we can only wait if we are in connected state
799 while ( d->state() == Socket::ConnectedState && bytesAvailable() <= 0 ) {
800 int rEvents = 0;
801 if ( EventDispatcher::waitForFdEvent( d->_socket, AbstractEventSource::Read | AbstractEventSource::Error , rEvents, timeout ) ) {
802 d->onSocketActivated( rEvents );
803 } else {
804 //timeout
805 return false;
806 }
807 }
808 return bytesAvailable() > 0;
809 }
810
811 int64_t Socket::readData( uint channel, char *buffer, int64_t bufsize )
812 {
813 if ( channel != 0 ) {
814 constexpr std::string_view msg("Socket does not support multiple read channels");
815 ERR << msg << std::endl;
816 throw std::logic_error( msg.data() );
817 }
818
819 Z_D();
820 if ( d->state() != SocketState::ConnectedState )
821 return -1;
822
823 const auto read = eintrSafeCall( ::read, d->_socket, buffer, bufsize );
824
825 // special case for remote close
826 if ( read == 0 ) {
827 d->setError( ConnectionClosedByRemote, "The remote host closed the connection", false );
828 return 0;
829 } else if ( read < 0 ) {
830 switch ( errno ) {
831#if EAGAIN != EWOULDBLOCK
832 case EWOULDBLOCK:
833#endif
834 case EAGAIN: {
835 return -2;
836 }
837 default: {
838 d->setError( UnknownSocketError, strerr_cxx( errno ), false );
839 return -1;
840 }
841 }
842 }
843 return read;
844 }
845
846 void Socket::readChannelChanged ( uint channel )
847 {
848 if ( channel != 0 ) {
849 constexpr std::string_view msg("Changing the readChannel on a Socket is not supported");
850 ERR << msg << std::endl;
851 throw std::logic_error( msg.data() );
852 }
853 }
854
855 int64_t Socket::bytesPending() const
856 {
857 Z_D();
858 return std::visit([&]( const auto &s ) -> int64_t {
859 using T = std::decay_t<decltype (s)>;
860 if constexpr ( std::is_same_v<T, SocketPrivate::ConnectedState> || std::is_same_v<T, SocketPrivate::ClosingState> ) {
861 return s._writeBuffer.size();
862 }
863 return 0;
864 }, d->_state );
865 }
866
867 Socket::SocketState Socket::state() const
868 {
869 return d_func()->state();
870 }
871
872 SignalProxy<void ()> Socket::sigIncomingConnection()
873 {
874 return d_func()->_incomingConnection;
875 }
876
877 SignalProxy<void ()> Socket::sigConnected()
878 {
879 return d_func()->_connected;
880 }
881
882 SignalProxy<void ()> Socket::sigDisconnected()
883 {
884 return d_func()->_disconnected;
885 }
886
887 SignalProxy<void (Socket::SocketError)> Socket::sigError()
888 {
889 return d_func()->_sigError;
890 }
891
892}
zyppng::AbstractEventSource::Error
@ Error
Definition abstracteventsource.h:50
zyppng::AbstractEventSource::Read
@ Read
Definition abstracteventsource.h:47
zyppng::AbstractEventSource::Write
@ Write
Definition abstracteventsource.h:48
zyppng::EventDispatcher::waitForFdEvent
static bool waitForFdEvent(const int fd, int events, int &revents, int &timeout)
Definition eventdispatcher_glib.cc:493
zyppng::IOBuffer
Definition iobuffer_p.h:10
zyppng::IODevicePrivate::_sigAllBytesWritten
Signal< void()> _sigAllBytesWritten
Definition iodevice_p.h:47
zyppng::IODevicePrivate::_sigBytesWritten
Signal< void(int64_t)> _sigBytesWritten
Definition iodevice_p.h:46
zyppng::IODevicePrivate::_readChannels
std::vector< IOBuffer > _readChannels
Definition iodevice_p.h:39
zyppng::IODevicePrivate::_readyRead
Signal< void() > _readyRead
Definition iodevice_p.h:44
zyppng::IODevicePrivate::_channelReadyRead
Signal< void(uint) > _channelReadyRead
Definition iodevice_p.h:45
zyppng::IODevice::bytesAvailable
virtual int64_t bytesAvailable() const
Definition iodevice.cc:109
zyppng::IODevice::WriteOnly
@ WriteOnly
Definition iodevice.h:40
zyppng::IODevice::ReadOnly
@ ReadOnly
Definition iodevice.h:39
zyppng::IODevice::read
ByteArray read(int64_t maxSize)
Definition iodevice.cc:127
zyppng::IODevice::IODevice
IODevice()
Definition iodevice.cc:10
zyppng::SignalProxy
Definition signals.h:325
zyppng::SocketNotifier::create
static Ptr create(int socket, int evTypes, bool enable=true)
Definition socketnotifier.cc:33
zyppng::SocketNotifier::sigActivated
SignalProxy< void(const SocketNotifier &sock, int evTypes)> sigActivated()
Definition socketnotifier.cc:76
zyppng::SocketPrivate
Definition socket_p.h:29
zyppng::SocketPrivate::_type
int _type
Definition socket_p.h:58
zyppng::SocketPrivate::state
Socket::SocketState state() const
Definition socket.cc:413
zyppng::SocketPrivate::_domain
int _domain
Definition socket_p.h:57
zyppng::SocketPrivate::wrapSocket
static Socket::Ptr wrapSocket(int fd, int domain, int type, int protocol, Socket::SocketState state)
Definition socket.cc:418
zyppng::SocketPrivate::_errorDesc
std::string _errorDesc
Definition socket_p.h:68
zyppng::SocketPrivate::_protocol
int _protocol
Definition socket_p.h:59
zyppng::SocketPrivate::initSocket
bool initSocket()
Definition socket.cc:21
zyppng::SocketPrivate::_state
std::variant< InitialState, ConnectingState, ConnectedState, ListeningState, ClosingState, ClosedState > _state
Definition socket_p.h:117
zyppng::SocketPrivate::connectToHost
bool connectToHost()
Definition socket.cc:143
zyppng::SocketPrivate::transition
bool transition(Socket::SocketState newState)
Definition socket.cc:72
zyppng::SocketPrivate::rawBytesAvailable
int64_t rawBytesAvailable() const
Definition socket.cc:202
zyppng::SocketPrivate::readRawBytesToBuffer
bool readRawBytesToBuffer()
Definition socket.cc:210
zyppng::SocketPrivate::handleConnectError
bool handleConnectError(int error)
Definition socket.cc:300
zyppng::SocketPrivate::_disconnected
Signal< void()> _disconnected
Definition socket_p.h:74
zyppng::SocketPrivate::onSocketActivated
void onSocketActivated(int ev)
Definition socket.cc:343
zyppng::SocketPrivate::_targetAddr
std::shared_ptr< SockAddr > _targetAddr
Definition socket_p.h:60
zyppng::SocketPrivate::_connected
Signal< void()> _connected
Definition socket_p.h:73
zyppng::SocketPrivate::setError
void setError(Socket::SocketError error, std::string &&err, bool emit=true)
Definition socket.cc:60
zyppng::SocketPrivate::onSocketActivatedSlot
void onSocketActivatedSlot(const SocketNotifier &, int ev)
Definition socket_p.h:50
zyppng::SocketPrivate::writePendingData
bool writePendingData()
Definition socket.cc:253
zyppng::SocketPrivate::_socket
int _socket
Definition socket_p.h:62
zyppng::SocketPrivate::_incomingConnection
Signal< void()> _incomingConnection
Definition socket_p.h:72
zyppng::SocketPrivate::_borrowedSocket
bool _borrowedSocket
Definition socket_p.h:63
zyppng::SocketPrivate::_emittedErr
bool _emittedErr
Definition socket_p.h:66
zyppng::SocketPrivate::_sigError
Signal< void(Socket::SocketError)> _sigError
Definition socket_p.h:71
zyppng::SocketPrivate::_error
Socket::SocketError _error
Definition socket_p.h:67
zyppng::Socket
Definition socket.h:36
zyppng::Socket::lastError
SocketError lastError() const
Definition socket.cc:653
zyppng::Socket::sigConnected
SignalProxy< void()> sigConnected()
Definition socket.cc:877
zyppng::Socket::abort
void abort()
Definition socket.cc:659
zyppng::Socket::close
void close() override
Definition socket.cc:665
zyppng::Socket::connect
bool connect(std::shared_ptr< SockAddr > addr)
Definition socket.cc:619
zyppng::Socket::fromSocket
static Ptr fromSocket(int fd, SocketState state)
Definition socket.cc:564
zyppng::Socket::SocketError
SocketError
Definition socket.h:40
zyppng::Socket::InternalError
@ InternalError
Definition socket.h:59
zyppng::Socket::ConnectionDelayed
@ ConnectionDelayed
Definition socket.h:55
zyppng::Socket::AddressNotAvailable
@ AddressNotAvailable
Definition socket.h:51
zyppng::Socket::UnknownSocketError
@ UnknownSocketError
Definition socket.h:42
zyppng::Socket::AddressInUse
@ AddressInUse
Definition socket.h:50
zyppng::Socket::NoError
@ NoError
Definition socket.h:41
zyppng::Socket::AddressIssue
@ AddressIssue
Definition socket.h:52
zyppng::Socket::OperationNotSupported
@ OperationNotSupported
Definition socket.h:53
zyppng::Socket::ConnectionRefused
@ ConnectionRefused
Definition socket.h:56
zyppng::Socket::UnsupportedSocketOptions
@ UnsupportedSocketOptions
Definition socket.h:46
zyppng::Socket::InsufficientRessources
@ InsufficientRessources
Definition socket.h:45
zyppng::Socket::InsufficientPermissions
@ InsufficientPermissions
Definition socket.h:43
zyppng::Socket::InvalidSocketOptions
@ InvalidSocketOptions
Definition socket.h:44
zyppng::Socket::ConnectionTimeout
@ ConnectionTimeout
Definition socket.h:54
zyppng::Socket::SocketAlreadyBound
@ SocketAlreadyBound
Definition socket.h:48
zyppng::Socket::NetworkUnreachable
@ NetworkUnreachable
Definition socket.h:58
zyppng::Socket::FailedSocketOperation
@ FailedSocketOperation
Definition socket.h:47
zyppng::Socket::ConnectionClosedByRemote
@ ConnectionClosedByRemote
Definition socket.h:57
zyppng::Socket::readChannelChanged
void readChannelChanged(uint channel) override
Definition socket.cc:846
zyppng::Socket::SocketState
SocketState
Definition socket.h:62
zyppng::Socket::ConnectedState
@ ConnectedState
Definition socket.h:65
zyppng::Socket::ClosedState
@ ClosedState
Definition socket.h:68
zyppng::Socket::ConnectingState
@ ConnectingState
Definition socket.h:64
zyppng::Socket::InitialState
@ InitialState
Definition socket.h:63
zyppng::Socket::ListeningState
@ ListeningState
Definition socket.h:66
zyppng::Socket::ClosingState
@ ClosingState
Definition socket.h:67
zyppng::Socket::waitForReadyRead
bool waitForReadyRead(uint channel, int timeout=-1) override
Definition socket.cc:792
zyppng::Socket::nativeSocket
int nativeSocket() const
Definition socket.cc:638
zyppng::Socket::disconnect
void disconnect()
Definition socket.cc:670
zyppng::Socket::releaseSocket
int releaseSocket()
Definition socket.cc:644
zyppng::Socket::create
static Ptr create(int domain, int type, int protocol)
Definition socket.cc:458
zyppng::Socket::sigDisconnected
SignalProxy< void()> sigDisconnected()
Definition socket.cc:882
zyppng::Socket::sigIncomingConnection
SignalProxy< void()> sigIncomingConnection()
Definition socket.cc:872
zyppng::Socket::waitForAllBytesWritten
bool waitForAllBytesWritten(int timeout=-1)
Definition socket.cc:759
zyppng::Socket::listen
bool listen(int backlog=50)
Definition socket.cc:509
zyppng::Socket::sigError
SignalProxy< void(Socket::SocketError)> sigError()
Definition socket.cc:887
zyppng::Socket::Socket
Socket(int domain, int type, int protocol)
Definition socket.cc:439
zyppng::Socket::setBlocking
bool setBlocking(const bool set=true)
Definition socket.cc:597
zyppng::Socket::writeData
int64_t writeData(const char *data, int64_t count) override
Definition socket.cc:687
zyppng::Socket::accept
Ptr accept()
Definition socket.cc:538
zyppng::Socket::bytesPending
int64_t bytesPending() const override
Definition socket.cc:855
zyppng::Socket::~Socket
~Socket() override
Definition socket.cc:453
zyppng::Socket::waitForConnected
bool waitForConnected(int timeout=-1)
Definition socket.cc:741
zyppng::Socket::Ptr
std::shared_ptr< Socket > Ptr
Definition socket.h:71
zyppng::Socket::bind
bool bind(const std::shared_ptr< SockAddr > &addr)
Definition socket.cc:463
zyppng::Socket::readData
int64_t readData(uint channel, char *buffer, int64_t bufsize) override
Definition socket.cc:811
zyppng::Socket::rawBytesAvailable
int64_t rawBytesAvailable(uint channel=0) const override
Definition socket.cc:443
zyppng::Socket::state
SocketState state() const
Definition socket.cc:867
zyppng::Timer::create
static std::shared_ptr< Timer > create()
Creates a new Timer object, the timer is not started at this point.
Definition timer.cc:52
zyppng::Timer::sigExpired
SignalProxy< void(Timer &t)> sigExpired()
This signal is always emitted when the timer expires.
Definition timer.cc:120
linuxhelpers_p.h
std
Definition Arch.h:364
std::decay_t
typename decay< T >::type decay_t
Definition TypeTraits.h:42
zyppng
Definition MediaNetworkRequestExecutor.h:16
zyppng::eintrSafeCall
auto eintrSafeCall(Fun &&function, Args &&... args)
Definition linuxhelpers_p.h:50
zyppng::bytesAvailableOnFD
int64_t bytesAvailableOnFD(int fd)
Definition linuxhelpers.cc:62
zyppng::strerr_cxx
std::string strerr_cxx(const int err=-1)
Definition linuxhelpers_p.h:14
socket_p.h
string.h
zyppng::SocketPrivate::ClosedState
Definition socket_p.h:114
zyppng::SocketPrivate::ClosingState
Definition socket_p.h:106
zyppng::SocketPrivate::ClosingState::_writeBuffer
IOBuffer _writeBuffer
Definition socket_p.h:111
zyppng::SocketPrivate::ClosingState::ClosingState
ClosingState(IOBuffer &&writeBuffer)
Definition socket.cc:17
zyppng::SocketPrivate::ClosingState::_socketNotifier
SocketNotifier::Ptr _socketNotifier
Definition socket_p.h:110
zyppng::SocketPrivate::ConnectedState
Definition socket_p.h:91
zyppng::SocketPrivate::ConnectedState::_socketNotifier
SocketNotifier::Ptr _socketNotifier
Definition socket_p.h:95
zyppng::SocketPrivate::ConnectingState
Definition socket_p.h:81
zyppng::SocketPrivate::ListeningState
Definition socket_p.h:99
zyppng::SocketPrivate::ListeningState::_socketNotifier
SocketNotifier::Ptr _socketNotifier
Definition socket_p.h:103
AutoDispose.h
Logger.h
DBG
#define DBG
Definition Logger.h:99
ERR
#define ERR
Definition Logger.h:102
ZYPP_IMPL_PRIVATE
#define ZYPP_IMPL_PRIVATE(Class)
Definition zyppglobal.h:92
Z_D
#define Z_D()
Definition zyppglobal.h:105
Z_Z
#define Z_Z()
Definition zyppglobal.h:106