tizen 2.3.1 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     char *errstr = NULL;
40     char errbuf[512] = {0,};
41     #ifdef _GNU_SOURCE
42         errstr = strerror_r(errno, errbuf, sizeof(errbuf));
43     #else
44         strerror_r(errno, errbuf, sizeof(errbuf));
45         errstr = errbuf;
46     #endif
47     LogError(function_name << " : " << errstr);
48     ThrowMsg(Exception::SocketStreamException, function_name << " : " << errstr);
49 }
50
51 void SocketStream::Read(size_t num, void * bytes){
52
53     if(NULL == bytes){
54         LogError("Null pointer to buffer");
55         ThrowMsg(Exception::SocketStreamException, "Null pointer to buffer");
56     }
57     
58     m_bytesRead += num;
59     
60     if(m_bytesRead > MAX_BUFFER){
61         LogError("Too big buffer requested!");
62         ThrowMsg(Exception::SocketStreamException, "Too big buffer requested!");
63     }
64
65     char part_buffer[MAX_BUFFER];
66     std::string whole_buffer;
67
68     fd_set rset, allset;
69     int max_fd;
70     ssize_t bytes_read = 0, bytes_to_read = (ssize_t) num;
71
72     timespec timeout;
73
74     max_fd = m_socketFd;
75     ++max_fd;
76
77     FD_ZERO(&allset);
78     FD_SET(m_socketFd, &allset);
79
80     int returned_value;
81         
82     char *errstr = NULL;
83     char errbuf[512] = {0,};
84
85     while(bytes_to_read != 0){
86         timeout.tv_sec = READ_TIEMOUT_SEC;
87         timeout.tv_nsec = READ_TIMEUOT_NSEC;
88         rset = allset;
89
90         if(-1 == (returned_value = pselect(max_fd, &rset, NULL, NULL, &timeout, NULL))){
91             if(errno == EINTR) continue;
92             throwWithErrnoMessage("pselect()");
93         }
94         if(0 == returned_value){
95             //This means pselect got timedout
96             //This is not a proper behavior in reading data from UDS
97             //And could mean we got corrupted connection
98             LogError("Couldn't read whole data. continue..");
99             continue;
100         }
101         if(FD_ISSET(m_socketFd, &rset)){
102             bytes_read = read(m_socketFd, part_buffer, num);
103             if(bytes_read <= 0){
104                 if(errno == ECONNRESET || errno == ENOTCONN || errno == ETIMEDOUT){
105                     #ifdef _GNU_SOURCE
106                         errstr = strerror_r(errno, errbuf, sizeof(errbuf));
107                     #else
108                         strerror_r(errno, errbuf, sizeof(errbuf));
109                         errstr = errbuf;
110                     #endif
111                     ThrowMsg(Exception::SocketStreamException,
112                             "Connection closed : " << errstr << ". Couldn't read whole data");
113                 }else if (errno != EAGAIN && errno != EWOULDBLOCK){
114                     throwWithErrnoMessage("read()");
115                 }
116             }
117
118             whole_buffer.append(part_buffer, bytes_read);
119             bytes_to_read-=bytes_read;
120             bytes_read = 0;
121             continue;
122         }
123
124     }
125     memcpy(bytes, whole_buffer.c_str(), num);
126 }
127
128 void SocketStream::Write(size_t num, const void * bytes){
129
130     if(NULL == bytes){
131         LogError("Null pointer to buffer");
132         ThrowMsg(Exception::SocketStreamException, "Null pointer to buffer");
133     }
134     
135     m_bytesWrote += num;
136     
137     if(m_bytesWrote > MAX_BUFFER){
138         LogError("Too big buffer requested!");
139         ThrowMsg(Exception::SocketStreamException, "Too big buffer requested!");
140     }
141
142     fd_set wset, allset;
143     int max_fd;
144
145     timespec timeout;
146
147     max_fd = m_socketFd;
148     ++max_fd;
149
150     FD_ZERO(&allset);
151     FD_SET(m_socketFd, &allset);
152
153     int returned_value;
154
155     int write_res, bytes_to_write = num;
156     unsigned int current_offset = 0;
157
158     char *errstr = NULL;
159     char errbuf[512] = {0,};
160
161     while(current_offset != num){
162         timeout.tv_sec = WRITE_TIMEOUT_SEC;
163         timeout.tv_nsec = WRITE_TIMEOUT_NSEC;
164         wset = allset;
165
166         if(-1 == (returned_value = pselect(max_fd, NULL, &wset, NULL, &timeout, NULL))){
167             if(errno == EINTR) continue;
168             throwWithErrnoMessage("pselect()");
169         }
170
171         if(FD_ISSET(m_socketFd, &wset)){
172             if(-1 == (write_res = write(m_socketFd, reinterpret_cast<const char *>(bytes) + current_offset, bytes_to_write))){
173                 if(errno == ECONNRESET || errno == EPIPE){
174                     #ifdef _GNU_SOURCE
175                         errstr = strerror_r(errno, errbuf, sizeof(errbuf));
176                     #else
177                         strerror_r(errno, errbuf, sizeof(errbuf));
178                         errstr = errbuf;
179                     #endif
180                     ThrowMsg(Exception::SocketStreamException,
181                             "Connection closed : " << errstr << ". Couldn't write whole data");
182
183                 }else if(errno != EAGAIN && errno != EWOULDBLOCK){
184                     throwWithErrnoMessage("write()");
185                 }
186             }
187             current_offset += write_res;
188             bytes_to_write -= write_res;
189         }
190     }
191 }