tizen 2.3 release
[framework/web/wearable/wrt-security.git] / socket_connection / connection / SocketStream.cpp
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file        SocketStream.cpp
18  * @author      Zofia Abramowska (z.abramowska@samsung.com)
19  * @version     1.0
20  * @brief       Implementation of socket stream class
21  */
22
23
24 #include <sys/socket.h>
25 #include <sys/select.h>
26 #include <errno.h>
27 #include <cstring>
28 #include <unistd.h>
29 #include <dpl/log/log.h>
30 #include "SocketStream.h"
31
32 #define READ_TIEMOUT_SEC 1
33 #define READ_TIMEUOT_NSEC 0
34 #define WRITE_TIMEOUT_SEC 0
35 #define WRITE_TIMEOUT_NSEC 100000000
36 #define MAX_BUFFER 10240
37
38 void SocketStream::throwWithErrnoMessage(std::string function_name){
39     LogError(function_name << " : " << strerror(errno));
40     ThrowMsg(Exception::SocketStreamException, function_name << " : " << strerror(errno));
41 }
42
43 void SocketStream::Read(size_t num, void * bytes){
44
45     if(NULL == bytes){
46         LogError("Null pointer to buffer");
47         ThrowMsg(Exception::SocketStreamException, "Null pointer to buffer");
48     }
49     
50     m_bytesRead += num;
51     
52     if(m_bytesRead > MAX_BUFFER){
53         LogError("Too big buffer requested!");
54         ThrowMsg(Exception::SocketStreamException, "Too big buffer requested!");
55     }
56
57     char part_buffer[MAX_BUFFER];
58     std::string whole_buffer;
59
60     fd_set rset, allset;
61     int max_fd;
62     ssize_t bytes_read = 0, bytes_to_read = (ssize_t) num;
63
64     timespec timeout;
65
66     max_fd = m_socketFd;
67     ++max_fd;
68
69     FD_ZERO(&allset);
70     FD_SET(m_socketFd, &allset);
71
72     int returned_value;
73
74     while(bytes_to_read != 0){
75         timeout.tv_sec = READ_TIEMOUT_SEC;
76         timeout.tv_nsec = READ_TIMEUOT_NSEC;
77         rset = allset;
78
79         if(-1 == (returned_value = pselect(max_fd, &rset, NULL, NULL, &timeout, NULL))){
80             if(errno == EINTR)
81                 continue;
82             else{
83                 LogInfo("pselect() : " << strerror(errno));
84             throwWithErrnoMessage("pselect()");
85             }
86         }
87         if(0 == returned_value){
88             //This means pselect got timedout
89             //This is not a proper behavior in reading data from UDS
90             //And could mean we got corrupted connection
91             LogError("Couldn't read whole data. continue..");
92             continue;
93         }
94         if(FD_ISSET(m_socketFd, &rset)){
95             bytes_read = read(m_socketFd, part_buffer, num);
96             if(bytes_read <= 0){
97                 if(errno == ECONNRESET || errno == ENOTCONN || errno == ETIMEDOUT){
98                     LogInfo("Connection closed : " << strerror(errno));
99                     ThrowMsg(Exception::SocketStreamException,
100                             "Connection closed : " << strerror(errno) << ". Couldn't read whole data");
101                 }else if (errno != EAGAIN && errno != EWOULDBLOCK){
102                     throwWithErrnoMessage("read()");
103                 }
104             }
105
106             whole_buffer.append(part_buffer, bytes_read);
107             bytes_to_read-=bytes_read;
108             bytes_read = 0;
109             continue;
110         }
111
112     }
113     memcpy(bytes, whole_buffer.c_str(), num);
114 }
115
116 void SocketStream::Write(size_t num, const void * bytes){
117
118     if(NULL == bytes){
119         LogError("Null pointer to buffer");
120         ThrowMsg(Exception::SocketStreamException, "Null pointer to buffer");
121     }
122     
123     m_bytesWrote += num;
124     
125     if(m_bytesWrote > MAX_BUFFER){
126         LogError("Too big buffer requested!");
127         ThrowMsg(Exception::SocketStreamException, "Too big buffer requested!");
128     }
129
130     fd_set wset, allset;
131     int max_fd;
132
133     timespec timeout;
134
135     max_fd = m_socketFd;
136     ++max_fd;
137
138     FD_ZERO(&allset);
139     FD_SET(m_socketFd, &allset);
140
141     int returned_value;
142
143     int write_res, bytes_to_write = num;
144     unsigned int current_offset = 0;
145
146     while(current_offset != num){
147         timeout.tv_sec = WRITE_TIMEOUT_SEC;
148         timeout.tv_nsec = WRITE_TIMEOUT_NSEC;
149         wset = allset;
150
151         if(-1 == (returned_value = pselect(max_fd, NULL, &wset, NULL, &timeout, NULL))){
152             if(errno == EINTR) continue;
153             throwWithErrnoMessage("pselect()");
154         }
155
156         if(FD_ISSET(m_socketFd, &wset)){
157             if(-1 == (write_res = write(m_socketFd, reinterpret_cast<const char *>(bytes) + current_offset, bytes_to_write))){
158                 if(errno == ECONNRESET || errno == EPIPE){
159                     LogInfo("Connection closed : " << strerror(errno));
160                     ThrowMsg(Exception::SocketStreamException,
161                             "Connection closed : " << strerror(errno) << ". Couldn't write whole data");
162
163                 }else if(errno != EAGAIN && errno != EWOULDBLOCK){
164                     throwWithErrnoMessage("write()");
165                 }
166             }
167             current_offset += write_res;
168             bytes_to_write -= write_res;
169         }
170     }
171 }