1 /*
2  * This file is part of Licq, an instant messaging client for UNIX.
3  * Copyright (C) 2012 Licq developers <licq-dev@googlegroups.com>
4  *
5  * Licq is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Licq is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Licq; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "socket.h"
21 
22 #include <cerrno>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include <licq/buffer.h>
28 #include <licq/logging/log.h>
29 
30 #include "gettext.h"
31 
32 using namespace LicqIcq;
33 using Licq::Buffer;
34 using Licq::gLog;
35 
SrvSocket(const Licq::UserId & userId)36 SrvSocket::SrvSocket(const Licq::UserId& userId)
37   : Licq::INetSocket(SOCK_STREAM, "SRV", userId)
38 {
39   // Empty
40 }
41 
~SrvSocket()42 SrvSocket::~SrvSocket()
43 {
44   // Empty
45 }
46 
47 /*-----SrvSocket::ReceivePacket------------------------------------------------
48  * Receive data on the socket.  Checks the buffer to see if it is empty, if
49  * so, then it will create it using either the size read in from the socket
50  * (the first two bytes available) or the given size.
51  *---------------------------------------------------------------------------*/
receiveFlap(Licq::Buffer & buf)52 bool SrvSocket::receiveFlap(Licq::Buffer& buf)
53 {
54   if (!buf.Empty())
55   {
56     gLog.error(tr("Internal error: %s: Called with full buffer (%lu bytes)."),
57         __func__, buf.getDataSize());
58     return true;
59   }
60 
61   int nBytesReceived = 0;
62   errno = 0;
63 
64   // Check if the buffer is empty
65   char *buffer = new char[6];
66   int nSixBytes = 0;
67   while (nSixBytes != 6)
68   {
69     nBytesReceived = read(myDescriptor, buffer + nSixBytes, 6 - nSixBytes);
70     if (nBytesReceived <= 0)
71     {
72       if (nBytesReceived == 0)
73         gLog.warning(tr("server socket was closed!!!\n"));
74       else
75       {
76         myErrorType = ErrorErrno;
77         gLog.warning(tr("Error during receiving from server socket:\n%s"),
78             errorStr().c_str());
79       }
80       delete[] buffer;
81       return false;
82     }
83     nSixBytes += nBytesReceived;
84   }
85 
86   // now we start to verify the FLAP header
87   if (buffer[0] != 0x2a)
88   {
89     gLog.warning(tr("Server send bad packet start code: %02x %02x %02x %02x %02x %02x"),
90         buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
91     myErrorType = ErrorErrno;
92     delete[] buffer;
93     return false;
94   }
95 
96   // DAW maybe verify sequence number ?
97 
98   unsigned short nLen = ((unsigned char)buffer[5]) + (((unsigned char)buffer[4]) << 8);
99 
100   // push the 6 bytes at the beginning of the packet again..
101   buf.Create(nLen + 6);
102   buf.packRaw(buffer, 6);
103   delete[] buffer;
104 
105   while (!buf.Full())
106   {
107     ssize_t bytesReceived = read(myDescriptor, buf.getDataPosWrite(), buf.remainingDataToWrite());
108     if (bytesReceived == 0 || (bytesReceived < 0 && errno != EINTR))
109     {
110       myErrorType = ErrorErrno;
111       return false;
112     }
113     buf.incDataPosWrite(bytesReceived);
114   }
115 
116   DumpPacket(&buf, true);
117 
118   return true;
119 }
120 
DcSocket(const Licq::UserId & userId)121 DcSocket::DcSocket(const Licq::UserId& userId)
122   : TCPSocket(userId),
123     myVersion(0)
124 {
125   // Empty
126 }
127 
DcSocket()128 DcSocket::DcSocket()
129 {
130   // Empty
131 }
132 
TransferConnectionFrom(Licq::TCPSocket & from)133 void DcSocket::TransferConnectionFrom(Licq::TCPSocket& from)
134 {
135   DcSocket* dcfrom = dynamic_cast<DcSocket*>(&from);
136   if (dcfrom != NULL)
137   {
138     myVersion = dcfrom->myVersion;
139   }
140 
141   Licq::TCPSocket::TransferConnectionFrom(from);
142 }
143 
RecvPacket()144 bool DcSocket::RecvPacket()
145 {
146   if (myRecvBuffer.Full())
147     return true;
148 
149   if (myRecvBuffer.Empty() || myRecvBuffer.getDataSize() < 2)
150   {
151     // Get header for next packet
152     if (!receive(myRecvBuffer, 2, false))
153       return false;
154 
155     if (myRecvBuffer.getDataSize() < 2)
156     {
157       // Didn't get a full header, retry later
158       return true;
159     }
160 
161     // Parse packet header
162     int length = myRecvBuffer.unpackUInt16LE();
163 
164     // Handle empty packets in case we ever get one
165     if (length == 0)
166     {
167       DumpPacket(&myRecvBuffer, true);
168       return true;
169     }
170 
171     // Resize buffer to hold entire packet including the header
172     myRecvBuffer.Create(length + 2);
173     myRecvBuffer.packUInt16LE(length);
174   }
175 
176   if (!receive(myRecvBuffer, myRecvBuffer.remainingDataToWrite()))
177     return false;
178 
179   return true;
180 }
181